﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

Функция ПроверитьАдрес(Адрес, ПараметрыПроверкиАдреса = Неопределено) Экспорт
	
	РезультатПроверки = РезультатПроверки(); 
	
	Если ТипЗнч(Адрес) <> Тип("Строка") Тогда
		РезультатПроверки.Результат = "СодержитОшибки";
		РезультатПроверки.СписокОшибок.Добавить("ФорматАдреса", НСтр("ru = 'Некорректный формат адреса'"));
		Возврат РезультатПроверки;
	КонецЕсли;
	
	Если Метаданные.Обработки.Найти("РасширенныйВводКонтактнойИнформации") <> Неопределено Тогда
		Обработки["РасширенныйВводКонтактнойИнформации"].ПроверитьАдрес(Адрес, РезультатПроверки, ПараметрыПроверкиАдреса);
	КонецЕсли;
	
	Возврат РезультатПроверки;
	
КонецФункции

Функция ПреобразоватьКонтактнуюИнформациюВФорматJSON(СсылкаИлиОбъект, ТипОбъекта) Экспорт
	
	ОбъектИзменен = Ложь;
	Если ОбщегоНазначения.ЭтоСсылка(ТипОбъекта) Тогда
		Если Не СодержитПустыеПоляJSON(СсылкаИлиОбъект) Тогда
			Возврат Ложь;
		КонецЕсли;
		ОбъектИзменен = ЗаполнитьJSONПоляКонтактнойИнформацииДляСсылки(СсылкаИлиОбъект);
	Иначе
		ОбъектИзменен = ЗаполнитьJSONПоляКонтактнойИнформацииДляОбъекта(СсылкаИлиОбъект);
	КонецЕсли;
	
	Возврат ОбъектИзменен;
	
КонецФункции


// Ищет контакты с адресами электронной почты.
// 
// Параметры:
//  СтрокаПоиска - Строка - текст поиска
//  ОписанияКонтактов - Массив из см. НовоеОписаниеКонтакта
// Возвращаемое значение:
//   ТаблицаЗначений:
//   * Контакт               - ОпределяемыйТип.КонтактВзаимодействия - найденный контакт.
//   * Наименование          - Строка - наименование контакта.
//   * НаименованиеВладельца - Строка - наименование владельца контакта.
//   * Представление         - Строка - адрес электронной почты.
//   
//
Функция НайтиКонтактыСАдресамиЭлектроннойПочты(СтрокаПоиска, ОписанияКонтактов) Экспорт
	
	ТекстЗапроса = 
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ ПЕРВЫЕ 20
	|	СправочникКонтакт.Ссылка КАК Контакт,
	|	ПРЕДСТАВЛЕНИЕ(СправочникКонтакт.Ссылка) КАК Наименование,
	|	"""" КАК НаименованиеВладельца,
	|	ТаблицаКонтактнаяИнформация.АдресЭП КАК Представление
	|ИЗ
	|	Справочник.Пользователи КАК СправочникКонтакт
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи.КонтактнаяИнформация КАК ТаблицаКонтактнаяИнформация
	|		ПО (ТаблицаКонтактнаяИнформация.Ссылка = СправочникКонтакт.Ссылка)
	|			И (ТаблицаКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
	|			И (ТаблицаКонтактнаяИнформация.АдресЭП <> """")
	|ГДЕ
	|	НЕ СправочникКонтакт.ПометкаУдаления
	|	И (СправочникКонтакт.Наименование ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""
	|			ИЛИ ТаблицаКонтактнаяИнформация.АдресЭП ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""
	|			ИЛИ ТаблицаКонтактнаяИнформация.ДоменноеИмяСервера ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""
	|			ИЛИ ТаблицаКонтактнаяИнформация.Представление ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~"")";
	
	Для каждого ОписаниеКонтакта Из ОписанияКонтактов Цикл
		
		Если ОписаниеКонтакта.Имя = "Пользователи" Тогда
			Продолжить; // пропускаем
		КонецЕсли;
			
		УсловиеПолейВводаПоСтроке = "";
		МетаданныеОбъекта = Метаданные.НайтиПоТипу(ОписаниеКонтакта.Тип);
		СписокПолей = МетаданныеОбъекта.ВводПоСтроке; // СписокПолей
		Для Каждого Поле Из СписокПолей Цикл
			ПолеСтроковогоТипа = Ложь;
			Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(МетаданныеОбъекта.СтандартныеРеквизиты, Поле.Имя) Тогда 
				Если МетаданныеОбъекта.СтандартныеРеквизиты[Поле.Имя].Тип.Типы()[0] = Тип("Строка") Тогда
					ПолеСтроковогоТипа = Истина;
				КонецЕсли;
			ИначеЕсли ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(МетаданныеОбъекта.Реквизиты, Поле.Имя) Тогда 
				Если МетаданныеОбъекта.Реквизиты[Поле.Имя].Тип.Типы()[0] = Тип("Строка") Тогда
					ПолеСтроковогоТипа = Истина;
				КонецЕсли;
			КонецЕсли;
			Если ПолеСтроковогоТипа Тогда
				УсловиеПолейВводаПоСтроке = УсловиеПолейВводаПоСтроке + " " 
					+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						"ИЛИ СправочникКонтакт.%1 ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""",
						Поле.Имя);
			КонецЕсли;
		КонецЦикла;
		
		ТекстЗапроса = ТекстЗапроса + "
		|ОБЪЕДИНИТЬ ВСЕ
		|";
		
		ТекстЗапроса = ТекстЗапроса + "
		|ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 20
		|	СправочникКонтакт.Ссылка КАК Контакт,
		|	&ПолеНаименование КАК Наименование,
		|	&ПолеНаименованиеВладельца КАК НаименованиеВладельца,
		|	ТаблицаКонтактнаяИнформация.АдресЭП КАК Представление
		|ИЗ
		|	&ТаблицаСправочник КАК СправочникКонтакт
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИмяТаблицаКонтактнаяИнформация КАК ТаблицаКонтактнаяИнформация
		|		ПО (ТаблицаКонтактнаяИнформация.Ссылка = СправочникКонтакт.Ссылка)
		|			И (ТаблицаКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты) 
		|			И (ТаблицаКонтактнаяИнформация.АдресЭП <> """"))
		|ГДЕ
		|	НЕ СправочникКонтакт.ПометкаУдаления 
		|	И (ТаблицаКонтактнаяИнформация.АдресЭП ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""
		|		ИЛИ ТаблицаКонтактнаяИнформация.ДоменноеИмяСервера ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""
		|		ИЛИ ТаблицаКонтактнаяИнформация.Представление ПОДОБНО &ВведеннаяСтрока СПЕЦСИМВОЛ ""~""
		|		И &УсловиеПолейВводаПоСтроке) 
		|";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеНаименованиеВладельца" , ?(ОписаниеКонтакта.ЕстьВладелец, 
			"ПРЕДСТАВЛЕНИЕ(СправочникКонтакт.Владелец)", """"""));
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеНаименование" , "СправочникКонтакт." 
			+ ОписаниеКонтакта.ИмяРеквизитаПредставлениеКонтакта);
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТаблицаСправочник" ,"Справочник." + ОписаниеКонтакта.Имя);
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИмяТаблицаКонтактнаяИнформация" ,"Справочник." 
			+ ОписаниеКонтакта.Имя + ".КонтактнаяИнформация");
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "И &УсловиеПолейВводаПоСтроке" , УсловиеПолейВводаПоСтроке);
		
	КонецЦикла;
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("ВведеннаяСтрока", "%" + ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(СтрокаПоиска) + "%");
	Возврат Запрос.Выполнить().Выгрузить(); 
	
КонецФункции


// Новое описание контакта с адресами электронной почты для поиска.
//
// Возвращаемое значение:
//   Структура:
//     * Тип                               - Тип    - тип ссылки контакта.
//     * Имя                               - Строка - имя типа контакта , как оно определено в метаданных.
//     * ЕстьВладелец                      - Булево - признак того, что у контакта есть владелец.
//     * ИмяРеквизитаПредставлениеКонтакта - Строка - имя реквизита контакта, из которого будет получено
//                                                    представление контакта. Если не указано, то используется
//                                                    стандартный реквизит Наименование.
//
Функция НовоеОписаниеКонтакта() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Тип",                               "");
	Результат.Вставить("Имя",                               "");
	Результат.Вставить("ЕстьВладелец",                      Ложь);
	Результат.Вставить("ИмяРеквизитаПредставлениеКонтакта", "Наименование");
	Возврат Результат;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ВерсионированиеОбъектовПереопределяемый.ПриПодготовкеДанныхОбъекта.
Процедура ПриПодготовкеДанныхОбъекта(Объект, ДополнительныеРеквизиты) Экспорт 
	
	Если Объект.Метаданные().ТабличныеЧасти.Найти("КонтактнаяИнформация") <> Неопределено Тогда
		КонтактнаяИнформацияОбъекта = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(Объект.Ссылка,, ТекущаяДатаСеанса(), Ложь);
		ВидыКИНаименование = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(КонтактнаяИнформацияОбъекта.ВыгрузитьКолонку("Вид"), "Наименование");
		Для Каждого Контакт Из КонтактнаяИнформацияОбъекта Цикл
			Если ЗначениеЗаполнено(Контакт.Вид) Тогда
				Реквизит = ДополнительныеРеквизиты.Добавить();
				Реквизит.Наименование = ВидыКИНаименование.Получить(Контакт.Вид);
				Реквизит.Значение = Контакт.Представление;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// См. ЗагрузкаДанныхИзФайлаПереопределяемый.ПриОпределенииСправочниковДляЗагрузкиДанных.
Процедура ПриОпределенииСправочниковДляЗагрузкиДанных(ЗагружаемыеСправочники) Экспорт
	
	// Загрузка в классификатор стран мира запрещена.
	СтрокаТаблицы = ЗагружаемыеСправочники.Найти(Метаданные.Справочники.СтраныМира.ПолноеИмя(), "ПолноеИмя");
	Если СтрокаТаблицы <> Неопределено Тогда 
		ЗагружаемыеСправочники.Удалить(СтрокаТаблицы);
	КонецЕсли;
	
КонецПроцедуры

// См. ЗапретРедактированияРеквизитовОбъектовПереопределяемый.ПриОпределенииОбъектовСЗаблокированнымиРеквизитами.
Процедура ПриОпределенииОбъектовСЗаблокированнымиРеквизитами(Объекты) Экспорт
	
	Объекты.Вставить(Метаданные.Справочники.ВидыКонтактнойИнформации.ПолноеИмя(), "");
	
КонецПроцедуры

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт
	Объекты.Вставить(Метаданные.Справочники.ВидыКонтактнойИнформации.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке");
КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия    = "2.2.3.34";
	Обработчик.Процедура = "УправлениеКонтактнойИнформациейСлужебный.ОбновитьСуществующиеСтраныМира";
	Обработчик.РежимВыполнения = "Монопольно";
	Обработчик.ОбщиеДанные      = Ложь;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия    = "2.3.1.8";
	Обработчик.Процедура = "УправлениеКонтактнойИнформациейСлужебный.ОбновитьНастройкуДобавочногоНомераТелефона";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные      = Ложь;
	Обработчик.НачальноеЗаполнение = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия    = "2.3.1.15";
	Обработчик.Процедура = "УправлениеКонтактнойИнформациейСлужебный.УстановитьЗначениеПризнакаИспользуется";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные      = Ложь;
	Обработчик.НачальноеЗаполнение = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия          = "3.1.8.270";
	Обработчик.Идентификатор   = Новый УникальныйИдентификатор("22f43dca-ac4f-3289-81a9-e110cd56f8b2");
	Обработчик.Процедура       = "Справочники.ВидыКонтактнойИнформации.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ВидыКонтактнойИнформации.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты    = "Справочник.ВидыКонтактнойИнформации";
	Обработчик.ИзменяемыеОбъекты  = "Справочник.ВидыКонтактнойИнформации";
	Обработчик.БлокируемыеОбъекты = "Справочник.ВидыКонтактнойИнформации";
	Обработчик.ПроцедураПроверки  = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.Комментарий = НСтр("ru = 'Обновление видов контактной информации.
		|До завершения обработки виды контактной информации в документах в ряде случаев будут отображаться некорректно.'");
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
		Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
		НоваяСтрока = Обработчик.ПриоритетыВыполнения.Добавить();
		НоваяСтрока.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию";
		НоваяСтрока.Порядок = "До";
	КонецЕсли;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия          = "3.1.3.148";
	Обработчик.Идентификатор   = Новый УникальныйИдентификатор("dfc6a0fa-7c7b-4096-9d04-2c67d5eb17a4");
	Обработчик.Процедура       = "Справочники.СтраныМира.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.СтраныМира.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты    = "Справочник.СтраныМира";
	Обработчик.ИзменяемыеОбъекты  = "Справочник.СтраныМира";
	Обработчик.БлокируемыеОбъекты = "Справочник.СтраныМира";
	Обработчик.ПроцедураПроверки  = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.Комментарий = НСтр("ru = 'Обновление сведений о странах мирах в соответствии с общероссийским классификатором стран мира.
		|До завершения обработки наименование стран в документах в ряде случаев будет отображаться некорректно.'");

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
		Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
		НоваяСтрока = Обработчик.ПриоритетыВыполнения.Добавить();
		НоваяСтрока.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию";
		НоваяСтрока.Порядок = "До";
	КонецЕсли;
	
КонецПроцедуры

// См. ПоискИУдалениеДублейПереопределяемый.ПриОпределенииОбъектовСПоискомДублей.
Процедура ПриОпределенииОбъектовСПоискомДублей(Объекты) Экспорт
	
	Объекты.Вставить(Метаданные.Справочники.ВидыКонтактнойИнформации.ПолноеИмя(), "");
	
КонецПроцедуры

// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек
//
// Параметры:
//  Объекты - Массив из ОбъектМетаданных
//
Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт
	
	Объекты.Добавить(Метаданные.Справочники.СтраныМира);
	Объекты.Добавить(Метаданные.Справочники.ВидыКонтактнойИнформации);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса.
Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт
	Обработчики.Вставить("ИнтерактивнаяПроверкаЗаполненияКонтактнойИнформации", "УправлениеКонтактнойИнформациейСлужебный.УстановкаПараметровСеанса");
КонецПроцедуры

// См. КонтрольВеденияУчетаПереопределяемый.ПриОпределенииПроверок.
Процедура ПриОпределенииПроверок(ГруппыПроверок, Проверки) Экспорт
	
	ГруппаПроверок = ГруппыПроверок.Добавить();
	ГруппаПроверок.Наименование                 = НСтр("ru = 'Контактная информация'");
	ГруппаПроверок.Идентификатор                = "КонтактнаяИнформация";
	ГруппаПроверок.КонтекстПроверокВеденияУчета = "_КонтактнаяИнформация";
	
	Проверка = Проверки.Добавить();
	Проверка.ИдентификаторГруппы          = "КонтактнаяИнформация";
	Проверка.Наименование                 = НСтр("ru = 'Выявление некорректных настроек видов контактной информации'");
	Проверка.Причины                      = НСтр("ru = 'В карточке или документе отсутствуют поля контактной информации, или возникает ситуация, блокирующая работу с ними.'");
	Проверка.Рекомендация                 = НСтр("ru = 'Выполнить частичное автоматическое восстановление видов контактной информации (для этого нажать ссылку ниже).
	|
	|Если работа ведется в распределенной информационной базе (РИБ), то исправление следует запускать только в главном узле.
	|Затем выполнить синхронизацию с подчиненными узлами.'");
	Проверка.Идентификатор                = "КонтактнаяИнформация.ПроверитьИИсправитьВидыКонтактнойИнформации";
	Проверка.ОбработчикПроверки           = "УправлениеКонтактнойИнформациейСлужебный.ПроверитьВидыКонтактнойИнформации";
	Проверка.ОбработчикПереходаКИсправлению = "Справочник.ВидыКонтактнойИнформации.Форма.ИсправлениеВидовКонтактнойИнформации";
	Проверка.КонтекстПроверокВеденияУчета = "_КонтактнаяИнформация";
	Проверка.Отключена                    = Истина;
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		МодульРаботаСАдресами.ПриОпределенииПроверок(ГруппыПроверок, Проверки);
	КонецЕсли;
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриПолученииСпискаШаблонов.
Процедура ПриПолученииСпискаШаблонов(ШаблоныЗаданий) Экспорт
	
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.ИсправлениеУстаревшихАдресов.Имя);
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.
Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт
	СоответствиеИменПсевдонимам.Вставить("УправлениеКонтактнойИнформациейСлужебный.ИсправлениеУстаревшихАдресов");
КонецПроцедуры

// См. МультиязычностьСервер.ОбъектыСТЧПредставления
Процедура ПриОпределенииОбъектовСТабличнойЧастьюПредставление(Объекты) Экспорт
	Объекты.Добавить("Справочник.ВидыКонтактнойИнформации");
КонецПроцедуры

Функция ВидыКонтактнойИнформацииОбновляются(Очередь) Экспорт
	Возврат ОбновлениеИнформационнойБазы.ЕстьЗаблокированныеПредыдущимиОчередямиДанные(Очередь, "Справочник.ВидыКонтактнойИнформации");
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция СодержитПустыеПоляJSON(ПроверяемыйОбъект)
	
	ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ПроверяемыйОбъект));
	Если ОбъектМетаданных = Неопределено Тогда
		Возврат Истина;
	КонецЕсли;
	
	ШаблонЗапроса = "ВЫБРАТЬ ПЕРВЫЕ 1
		|	ТаблицаСКонтактнойИнформацией.Ссылка КАК Ссылка
		|ИЗ
		|	&ПолноеИмяОбъектаСКонтактнойИнформацией КАК ТаблицаСКонтактнойИнформацией
		|ГДЕ
		|	(ВЫРАЗИТЬ(ТаблицаСКонтактнойИнформацией.Значение КАК СТРОКА(1))) = """"
		|	И ТаблицаСКонтактнойИнформацией.Ссылка = &Ссылка";
	
	НаборТекстаЗапроса = СтрЗаменить(ШаблонЗапроса, "&ПолноеИмяОбъектаСКонтактнойИнформацией",
			ОбъектМетаданных.ПолноеИмя() + ".КонтактнаяИнформация");
			
	Запрос = Новый Запрос(НаборТекстаЗапроса);
	Запрос.УстановитьПараметр("Ссылка", ПроверяемыйОбъект);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Возврат Не РезультатЗапроса.Пустой();
	
КонецФункции

Функция ЗаполнитьJSONПоляКонтактнойИнформацииДляСсылки(Ссылка)
	
	ОбъектИзменен = Ложь;
	
	ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
	
	НачатьТранзакцию();
	Попытка
	
		Блокировка.Заблокировать();
		Объект = Ссылка.ПолучитьОбъект();
		Объект.Заблокировать();
		
		Если ЗаполнитьJSONПоляКонтактнойИнформацииДляОбъекта(Объект) Тогда
			ОбъектИзменен = Истина;
			Объект.Записать();
		КонецЕсли;
		ЗафиксироватьТранзакцию();
		
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Возврат ОбъектИзменен;
	
КонецФункции

Функция ЗаполнитьJSONПоляКонтактнойИнформацииДляОбъекта(ОбъектСКонтактнойИнформацией)
	
	ОбъектИзменен = Ложь;
	
	Для каждого СтрокаКонтактнойИнформации Из ОбъектСКонтактнойИнформацией.КонтактнаяИнформация Цикл
		
		Если ЗначениеЗаполнено(СтрокаКонтактнойИнформации.Значение)
			И УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(СтрокаКонтактнойИнформации.Значение) Тогда
			Продолжить;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(СтрокаКонтактнойИнформации.ЗначенияПолей) Тогда
			
			СтрокаКонтактнойИнформации.Значение = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(
				СтрокаКонтактнойИнформации.ЗначенияПолей, СтрокаКонтактнойИнформации.Тип);
		Иначе
			
			СтрокаКонтактнойИнформации.Значение = КонтактнаяИнформацияПоПредставлению(
				СтрокаКонтактнойИнформации.Представление, СтрокаКонтактнойИнформации.Тип);
			
		КонецЕсли;
		
		Если ЗначениеЗаполнено(СтрокаКонтактнойИнформации.Значение) Тогда
			ОбъектИзменен = Истина;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат ОбъектИзменен;

КонецФункции

Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка) Экспорт
	
	Если Не ЕстьПравоДобавления() Или Не УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
	ДанныеВыбора = МодульРаботаСАдресами.ЗаполнитьДанныеВыбораАвтоподбораПоСтранам(Параметры);
	СтандартнаяОбработка = Ложь;
	
КонецПроцедуры

Процедура АвтоподборАдреса(Знач Текст, ДанныеВыбора) Экспорт
	
	Если Метаданные.Обработки.Найти("РасширенныйВводКонтактнойИнформации") = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ДополнительныеПараметры = ПараметрыАвтоподбораАдреса();
	ДополнительныеПараметры.ТолькоВебСервис = Истина;
	
	Результат = Обработки["РасширенныйВводКонтактнойИнформации"].СписокАвтоподбораНаселенногоПункта(Текст, ДополнительныеПараметры);
	Если Результат.Отказ Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеВыбора = Результат.Данные;
	ФорматированиеРезультатовАвтоподбора(ДанныеВыбора, Текст);
	
КонецПроцедуры

Функция ПараметрыАвтоподбораАдреса() Экспорт
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ТолькоВебСервис", Ложь);
	ДополнительныеПараметры.Вставить("Уровни", "");
	ДополнительныеПараметры.Вставить("ТипАдреса", "");
	
	Возврат ДополнительныеПараметры;
	
КонецФункции

Процедура ФорматированиеРезультатовАвтоподбора(ДанныеВыбора, Знач Текст, ВыделятьУстаревшиеАдреса = Истина) Экспорт
	
	Если Не УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
	
	// Оформление списка поиска
	ФрагментыТекстаПоиска = СтрРазделить(Текст, " ");
	Для каждого СтрокаДанных Из ДанныеВыбора Цикл
		
		Если ТипЗнч(СтрокаДанных.Значение) = Тип("Структура")
			И СтрокаДанных.Значение.Свойство("Адрес") Тогда
			
			Если ЗначениеЗаполнено(СтрокаДанных.Значение.Адрес) И ТипЗнч(СтрокаДанных.Значение.Адрес) = Тип("Строка") Тогда
				Адрес = JSONВКонтактнуюИнформациюПоПолям(СтрокаДанных.Значение.Адрес, Перечисления.ТипыКонтактнойИнформации.Адрес);
				СтрокаДанных.Значение.Представление = МодульРаботаСАдресамиКлиентСервер.ПредставлениеАдреса(Адрес, Ложь);
			КонецЕсли;
			
		КонецЕсли;
		
		Представление = СтрокаДанных.Представление;
		Для каждого ФрагментТекстаПоиска Из ФрагментыТекстаПоиска Цикл
			ПредставлениеСВыделением = СтрНайтиИВыделитьОформлением(Представление, ФрагментТекстаПоиска);
			Если ПредставлениеСВыделением <> Неопределено Тогда
				Представление = ПредставлениеСВыделением;
			КонецЕсли;
		КонецЦикла;
		СтрокаДанных.Представление = Представление;
		
	КонецЦикла;

КонецПроцедуры

// Функция-конструктор результата проверки.
// 
// Возвращаемое значение:
//   Структура:
//   * СписокОшибок - СписокЗначений
//   * Результат - Строка
// 
Функция РезультатПроверки()
	
	РезультатПроверки = Новый Структура;
	РезультатПроверки.Вставить("Результат", "");
	РезультатПроверки.Вставить("СписокОшибок", Новый СписокЗначений);
	Возврат РезультатПроверки
	
КонецФункции

Функция ЭтоТипАдрес(ЗначениеТипа)
	Возврат СтрСравнить(ЗначениеТипа, Строка(ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес"))) = 0;
КонецФункции

Функция ИсправитьПорциюВидовКонтактнойИнформации(Знач ПроблемныеОбъекты, Проверка)
	
	ИсправленоОбъектов = 0; 
	
	ТекстЗапроса = "ВЫБРАТЬ
	|	ПроблемныеОбъекты.ПроблемныйОбъект КАК Ссылка
	|ПОМЕСТИТЬ ПроблемныеОбъекты
	|ИЗ
	| &ПроблемныеОбъекты КАК ПроблемныеОбъекты
	|ИНДЕКСИРОВАТЬ ПО
	| ПроблемныйОбъект
	|;
	|
	|ВЫБРАТЬ
	|	ВидыКонтактнойИнформации.Ссылка КАК Ссылка,
	|ВЫБОР
	|	КОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида <> """"
	|	ТОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида
	|	ИНАЧЕ ВидыКонтактнойИнформации.ИмяПредопределенныхДанных
	|КОНЕЦ КАК ИмяПредопределенногоВида
	|ИЗ
	|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
	|ГДЕ
	|	ВидыКонтактнойИнформации.ЭтоГруппа = ИСТИНА
	|;";
	
	ОбъектыМетаданных = ОбъектыСодержащиеКонтактнуюИнформацию();
	НаборТекстаЗапроса = Новый Массив;
	
	ШаблонЗапроса = "ВЫБРАТЬ
	|	МАКСИМУМ(КонтактнаяИнформация.Ссылка) КАК Ссылка,
	|	КонтактнаяИнформация.Вид КАК Вид
	|ИЗ
	|	ПроблемныеОбъекты КАК ПроблемныеОбъекты
	|		ЛЕВОЕ СОЕДИНЕНИЕ &ПолноеИмяОбъектаСКонтактнойИнформацией КАК КонтактнаяИнформация
	|		ПО (КонтактнаяИнформация.Вид = ПроблемныеОбъекты.Ссылка)
	|ГДЕ
	|	НЕ КонтактнаяИнформация.Ссылка ЕСТЬ NULL
	|
	|СГРУППИРОВАТЬ ПО
	|	КонтактнаяИнформация.Вид";
	
	Для каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
		НаборТекстаЗапроса.Добавить(СтрЗаменить(ШаблонЗапроса, "&ПолноеИмяОбъектаСКонтактнойИнформацией", 
		ОбъектМетаданных.Метаданные().ПолноеИмя() + ".КонтактнаяИнформация"));
	КонецЦикла;
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса + СтрСоединить(НаборТекстаЗапроса, Символы.ПС + " ОБЪЕДИНИТЬ ВСЕ " + Символы.ПС);
	Запрос.Параметры.Вставить("ПроблемныеОбъекты", ПроблемныеОбъекты);
	
	РезультатыЗапроса = Запрос.ВыполнитьПакет();
	
	ИменаГрупп = РезультатыЗапроса.Получить(1).Выгрузить();
	ИменаГрупп.Индексы.Добавить("ИмяПредопределенногоВида");
	
	РезультатЗапроса = РезультатыЗапроса.Получить(2);
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат ИсправленоОбъектов;
	КонецЕсли;
	
	СтрокаЗапроса = РезультатЗапроса.Выбрать();
	Пока СтрокаЗапроса.Следующий() Цикл
		
		СсылкаНаЭлемент = СтрокаЗапроса.Ссылка;
		ПолноеИмя = СсылкаНаЭлемент.Метаданные().ПолноеИмя();
		
		СтрокаСИменемГруппы = ИменаГрупп.Найти(СтрЗаменить(ПолноеИмя, ".", ""), "ИмяПредопределенногоВида"); // СправочникСсылка.ВидыКонтактнойИнформации
		Если СтрокаСИменемГруппы <> Неопределено Тогда
			
			НачатьТранзакцию();
			
			Попытка
				Блокировка = Новый БлокировкаДанных;
				ЭлементБлокировки = Блокировка.Добавить("Справочник.ВидыКонтактнойИнформации");
				ЭлементБлокировки.УстановитьЗначение("Ссылка", СтрокаЗапроса.Вид);
				Блокировка.Заблокировать();
				
				Объект = СтрокаЗапроса.Вид.ПолучитьОбъект();
				Если Объект = Неопределено Тогда
					ЗафиксироватьТранзакцию();
					Продолжить;
				КонецЕсли;
				
				ЗаблокироватьДанныеДляРедактирования(СтрокаЗапроса.Вид);
				
				Объект.Родитель = СтрокаСИменемГруппы.Ссылка;
				ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект);
				
				ИсправленоОбъектов = ИсправленоОбъектов + 1;
				
				ЗафиксироватьТранзакцию();
			Исключение
				ОтменитьТранзакцию();
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				Продолжить;
			КонецПопытки;
			
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтрольВеденияУчета") Тогда
				МодульКонтрольВеденияУчета = ОбщегоНазначения.ОбщийМодуль("КонтрольВеденияУчета");
				МодульКонтрольВеденияУчета.ОчиститьРезультатПроверки(СтрокаЗапроса.Вид, Проверка); 
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;

	Возврат ИсправленоОбъектов;
	
КонецФункции

Функция ОбъектыСодержащиеКонтактнуюИнформацию() Экспорт
	
	ОбъектыМетаданных = Новый Массив; // Массив из СправочникСсылка, ДокументСсылка
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ВидыКонтактнойИнформации.Ссылка,
	|ВЫБОР
	|	КОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида <> """"
	|	ТОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида
	|	ИНАЧЕ ВидыКонтактнойИнформации.ИмяПредопределенныхДанных
	|КОНЕЦ КАК ИмяПредопределенногоВида
	|ИЗ
	|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
	|ГДЕ
	|	ВидыКонтактнойИнформации.ЭтоГруппа = ИСТИНА";
	
	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		Если СтрНачинаетсяС(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, "Справочник") Тогда
			ИмяОбъекта = Сред(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, СтрДлина("Справочник") + 1);
			ОбъектыМетаданных.Добавить(Справочники[ИмяОбъекта].ПустаяСсылка());
		ИначеЕсли СтрНачинаетсяС(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, "Документ") Тогда
			ИмяОбъекта = Сред(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, СтрДлина("Документ") + 1);
			Если Метаданные.Документы.Найти(ИмяОбъекта) <> Неопределено Тогда
				ОбъектыМетаданных.Добавить(Документы[ИмяОбъекта].ПустаяСсылка());
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ОбъектыМетаданных; 

КонецФункции

Процедура ИсправитьВидыКонтактнойИнформацииВФоне(Знач ПараметрыПроверки, АдресХранилища = Неопределено) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтрольВеденияУчета") Тогда
		Возврат;
	КонецЕсли;
	
	МодульКонтрольВеденияУчета = ОбщегоНазначения.ОбщийМодуль("КонтрольВеденияУчета");
	Проверка = МодульКонтрольВеденияУчета.ПроверкаПоИдентификатору(ПараметрыПроверки.ИдентификаторПроверки);
	
	Если Не ЗначениеЗаполнено(Проверка) Тогда
		Возврат;
	КонецЕсли;
	
	ПроблемныеОбъекты = МодульКонтрольВеденияУчета.ПроблемныеОбъекты(Проверка);
	ВсегоОбъектов      = 0;
	ИсправленоОбъектов = 0;

	Пока ПроблемныеОбъекты.Количество() > 0 Цикл
		
		ПоследнийПроблемныйОбъект = ПроблемныеОбъекты.Получить(ПроблемныеОбъекты.Количество() - 1).ПроблемныйОбъект;
		ВсегоОбъектов = ВсегоОбъектов + ПроблемныеОбъекты.Количество();
		// @skip-check query-in-loop - Порционная обработка больших объемов данных.
		ИсправленоОбъектов = ИсправленоОбъектов + ИсправитьПорциюВидовКонтактнойИнформации(ПроблемныеОбъекты, Проверка);
		ПроблемныеОбъекты = МодульКонтрольВеденияУчета.ПроблемныеОбъекты(Проверка, ПоследнийПроблемныйОбъект);
	
	КонецЦикла;
	Результат = Новый Структура;
	Результат.Вставить("ВсегоОбъектов", ВсегоОбъектов);
	Результат.Вставить("ИсправленоОбъектов", ИсправленоОбъектов);
	
	ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
	
КонецПроцедуры

// Выполняет проверку и исправление некорректных видов контактной информации.
//
// Параметры:
//   Проверка            - СправочникСсылка.ПравилаПроверкиУчета - исполняемая проверка.
//   ПараметрыПроверки   - см. КонтрольВеденияУчета.ОписаниеПроблемы.ПараметрыПроверки
//
Процедура ПроверитьВидыКонтактнойИнформации(Проверка, ПараметрыПроверки) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтрольВеденияУчета") Тогда
		Возврат;
	КонецЕсли;
	
	МодульКонтрольВеденияУчета = ОбщегоНазначения.ОбщийМодуль("КонтрольВеденияУчета");
	
	ПроверяемыеОбъекты = Неопределено;
	ПараметрыПроверки.Свойство("ПроверяемыеОбъекты", ПроверяемыеОбъекты);
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
		|	ВидыКонтактнойИнформации.Ссылка КАК Ссылка,
		|	ВидыКонтактнойИнформации.Ссылка КАК Наименование,
		|ВЫБОР
		|	КОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида <> """"
		|	ТОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида
		|	ИНАЧЕ ВидыКонтактнойИнформации.ИмяПредопределенныхДанных
		|КОНЕЦ КАК ИмяПредопределенногоВида
		|ИЗ
		|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
		|ГДЕ
		|	ВидыКонтактнойИнформации.ЭтоГруппа = ЛОЖЬ 
		|	И (ВидыКонтактнойИнформации.Родитель = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ПустаяСсылка)
		|	ИЛИ ВидыКонтактнойИнформации.Родитель = НЕОПРЕДЕЛЕНО)";
	
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат;
	КонецЕсли;
	
	СтрокаИзЗапроса = РезультатЗапроса.Выбрать();
	
	ПараметрыВыполненияПроверки = МодульКонтрольВеденияУчета.ПараметрыВыполненияПроверки("КонтактнаяИнформация", НСтр("ru='Виды контактной информации'", ОбщегоНазначения.КодОсновногоЯзыка()));
	МодульКонтрольВеденияУчета.ОчиститьРезультатыПредыдущихПроверок(Проверка, ПараметрыВыполненияПроверки);
	
	ВидПроверки = МодульКонтрольВеденияУчета.ВидПроверки(ПараметрыВыполненияПроверки);
	
	Пока СтрокаИзЗапроса.Следующий() Цикл
		
		Если СтрНачинаетсяС(СтрокаИзЗапроса.ИмяПредопределенногоВида, "Удалить") Тогда
			Продолжить;
		КонецЕсли;
		
		Проблема = МодульКонтрольВеденияУчета.ОписаниеПроблемы(СтрокаИзЗапроса.Ссылка, ПараметрыПроверки);
		Проблема.ВидПроверки = ВидПроверки;
		Проблема.УточнениеПроблемы = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не заполнена группа определяющая владельца контактной информации'"), СтрокаИзЗапроса.Наименование);
		
		МодульКонтрольВеденияУчета.ЗаписатьПроблему(Проблема, ПараметрыПроверки);
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ИсправлениеУстаревшихАдресов() Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.ИсправлениеУстаревшихАдресов);
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		МодульРаботаСАдресами.ВыявитьИИсправитьУстаревшиеАдреса();
		
	КонецЕсли;
	
КонецПроцедуры

#Область ОбновлениеИнформационнойБазы

Процедура ОбновитьСуществующиеСтраныМира() Экспорт
	
	Если Не УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		Возврат;
	КонецЕсли;
	
	ВсеОшибки = "";
	Добавлять = Ложь;
	
	Фильтр = Новый Структура("Код");
	МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
	
	// Сравнивать в запросе нельзя из-за возможной регистронезависимости базы данных.
	Для Каждого СтрокаКлассификатора Из МодульРаботаСАдресами.ТаблицаКлассификатора() Цикл
		Фильтр.Код = СтрокаКлассификатора.Код;
		Выборка = Справочники.СтраныМира.Выбрать(,, Фильтр);
		СтранаНайдена = Выборка.Следующий();
		Если Не СтранаНайдена И Добавлять Тогда
			Страна = Справочники.СтраныМира.СоздатьЭлемент();
		ИначеЕсли СтранаНайдена И (
			Выборка.Наименование <> СтрокаКлассификатора.Наименование
			Или Выборка.КодАльфа2 <> СтрокаКлассификатора.КодАльфа2
			Или Выборка.КодАльфа3 <> СтрокаКлассификатора.КодАльфа3
			Или Выборка.НаименованиеПолное <> СтрокаКлассификатора.НаименованиеПолное) Тогда
			Страна = Выборка.ПолучитьОбъект();
		Иначе
			Продолжить;
		КонецЕсли;
		
		НачатьТранзакцию();
		Попытка
			Если Не Страна.ЭтоНовый() Тогда
				ЗаблокироватьДанныеДляРедактирования(Страна.Ссылка);
			КонецЕсли;
			ЗаполнитьЗначенияСвойств(Страна, СтрокаКлассификатора);
			Страна.ДополнительныеСвойства.Вставить("НеПроверятьУникальность");
			Страна.Записать();
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			Инфо = ИнформацияОбОшибке();
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Ошибка записи страны мира %1 (код %2) при обновлении классификатора, %3'"),
				Выборка.Код, Выборка.Наименование, ОбработкаОшибок.КраткоеПредставлениеОшибки(Инфо));
			ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(),
				УровеньЖурналаРегистрации.Ошибка,,,
				ТекстОшибки + Символы.ПС + ОбработкаОшибок.ПодробноеПредставлениеОшибки(Инфо));
			ВсеОшибки = ВсеОшибки + Символы.ПС + ТекстОшибки;
		КонецПопытки;
		
	КонецЦикла;
	
	Если Не ПустаяСтрока(ВсеОшибки) Тогда
		ВызватьИсключение СокрЛП(ВсеОшибки);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбновитьНастройкуДобавочногоНомераТелефона() Экспорт
	
	// Устанавливает флаг ТелефонСДобавочнымНомером для обратной совместимости.
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ВидыКонтактнойИнформации.Ссылка
		|ИЗ
		|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
		|ГДЕ
		|	ВидыКонтактнойИнформации.Тип =  Значение(Перечисление.ТипыКонтактнойИнформации.Телефон)";
	
	РезультатЗапроса = Запрос.Выполнить().Выбрать();
	
	Блокировка = Новый БлокировкаДанных();
	Блокировка.Добавить("Справочник.ВидыКонтактнойИнформации");
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка.Заблокировать();
	
		Пока РезультатЗапроса.Следующий() Цикл
			ВидКонтактнойИнформации = РезультатЗапроса.Ссылка.ПолучитьОбъект();
			ВидКонтактнойИнформации.ТелефонСДобавочнымНомером = Истина;
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(ВидКонтактнойИнформации);
		КонецЦикла;
		
		ЗафиксироватьТранзакцию();
		
	Исключение
		
		ОтменитьТранзакцию();
		ВызватьИсключение;
		
	КонецПопытки;
	
КонецПроцедуры

Процедура УстановитьЗначениеПризнакаИспользуется() Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	ВидыКонтактнойИнформации.Ссылка КАК Ссылка,
	|	ВидыКонтактнойИнформации.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных
	|ИЗ
	|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
	|ГДЕ
	|	НЕ ВидыКонтактнойИнформации.Используется";
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Блокировка = Новый БлокировкаДанных();
	Блокировка.Добавить("Справочник.ВидыКонтактнойИнформации");
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка.Заблокировать();
		
		Пока Выборка.Следующий() Цикл
			
			Если СтрНачинаетсяС(ВРег(Выборка.ИмяПредопределенныхДанных), "УДАЛИТЬ") Тогда
				Продолжить;
			КонецЕсли;
			
			ВидКонтактнойИнформацииОбъект = Выборка.Ссылка.ПолучитьОбъект();
			ВидКонтактнойИнформацииОбъект.Используется = Истина;
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(ВидКонтактнойИнформацииОбъект);
			
		КонецЦикла;
			ЗафиксироватьТранзакцию();
		
	Исключение
		
		ОтменитьТранзакцию();
		ВызватьИсключение;
		
	КонецПопытки;
	
КонецПроцедуры

// Обработчик события КонтактнаяИнформацияОбработкаПроверкиЗаполнения
// 
// Параметры:
//   Источник - СправочникОбъект
//            - ДокументОбъект
//   Отказ - Булево
//   ПроверяемыеРеквизиты - Массив
// 
Процедура КонтактнаяИнформацияОбработкаПроверкиЗаполнения(Источник, Отказ, ПроверяемыеРеквизиты) Экспорт
	
	Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ПравоДоступа("Чтение", Метаданные.Справочники.ВидыКонтактнойИнформации) Тогда
		Возврат;
	КонецЕсли;
	
	Если ПараметрыСеанса.ИнтерактивнаяПроверкаЗаполненияКонтактнойИнформации Тогда
		ПараметрыСеанса.ИнтерактивнаяПроверкаЗаполненияКонтактнойИнформации = Ложь;
		Возврат;
	КонецЕсли;
	
	// Контактная информация подключена к объекту.
	Проверка = Новый Структура;
	Проверка.Вставить("КонтактнаяИнформация", Неопределено);
	Проверка.Вставить("ЭтоГруппа", Ложь);
	ЗаполнитьЗначенияСвойств(Проверка, Источник);
	
	Если Проверка.КонтактнаяИнформация = Неопределено Или Проверка.ЭтоГруппа Тогда
		Возврат; // Табличная часть контактная информация отсутствует у объекта.
	КонецЕсли;
	
	ВидыКонтактнойИнформации = ВидыТребующиеОбязательногоЗаполнения(Источник.Ссылка);
	Сообщения = Новый Массив;
	
	Если ВидыКонтактнойИнформации.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Для каждого ВидКонтактнойИнформации Из ВидыКонтактнойИнформации Цикл
		Отбор = Новый Структура("Вид", ВидКонтактнойИнформации);
		НайденныеСтроки = Источник.КонтактнаяИнформация.НайтиСтроки(Отбор);
		
		Если НайденныеСтроки.Количество() = 0 Тогда
			
			Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Поле ""%1"" не заполнено.'"),
				ВидКонтактнойИнформации);
			Сообщения.Добавить(Текст);
			
		Иначе
			
			Для Каждого СтрокаКонтактнойИнформации Из НайденныеСтроки Цикл
				
				Если ПустаяСтрока(СтрокаКонтактнойИнформации.Представление)
					ИЛИ (ПустаяСтрока(СтрокаКонтактнойИнформации.Значение)
					И ПустаяСтрока(СтрокаКонтактнойИнформации.ЗначенияПолей)) Тогда
					
					Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Поле ""%1"" не заполнено.'"),
						СтрокаКонтактнойИнформации.Вид);
					Сообщения.Добавить(Текст);
					Прервать;
					
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЕсли;
		
	КонецЦикла;
		
	Если Сообщения.Количество() > 0 Тогда
		ОбщегоНазначения.СообщитьПользователю(СтрСоединить(Сообщения, Символы.ПС),,,, Отказ);
	КонецЕсли;
	
КонецПроцедуры

Функция ВидыТребующиеОбязательногоЗаполнения(ВладелецКонтактнойИнформации)
	
	ПолноеИмяОбъектаМетаданных = ВладелецКонтактнойИнформации .Метаданные().ПолноеИмя();
	
	ИмяГруппыВидовКИ = СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", "");
	ГруппаВидовКИ = Неопределено;
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	ВидыКонтактнойИнформации.Ссылка КАК Ссылка,
	|ВЫБОР
	|	КОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида <> """"
	|	ТОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида
	|	ИНАЧЕ ВидыКонтактнойИнформации.ИмяПредопределенныхДанных
	|КОНЕЦ КАК ИмяПредопределенногоВида
	|ИЗ
	|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
	|ГДЕ
	|	ВидыКонтактнойИнформации.ЭтоГруппа = ИСТИНА
	|	И ВидыКонтактнойИнформации.ПометкаУдаления = ЛОЖЬ
	|	И ВидыКонтактнойИнформации.Используется = ИСТИНА";
	
	РезультатЗапроса = Запрос.Выполнить().Выбрать();
	Пока РезультатЗапроса.Следующий() Цикл 
		Если СтрСравнить(РезультатЗапроса.ИмяПредопределенногоВида, ИмяГруппыВидовКИ) = 0 Тогда
			ГруппаВидовКИ = РезультатЗапроса.Ссылка;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если НЕ ЗначениеЗаполнено(ГруппаВидовКИ) Тогда
		Возврат Новый Массив;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ВидыКонтактнойИнформации.Ссылка
	|ИЗ
	|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
	|ГДЕ
	|	ВидыКонтактнойИнформации.Родитель = &ГруппаВидовКИ
	|	И ВидыКонтактнойИнформации.ПометкаУдаления = ЛОЖЬ
	|	И ВидыКонтактнойИнформации.Используется = ИСТИНА
	|	И ВидыКонтактнойИнформации.ОбязательноеЗаполнение = ИСТИНА";
	
	Запрос.УстановитьПараметр("ГруппаВидовКИ", ГруппаВидовКИ);
	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
	
КонецФункции

// Параметры:
//  ИмяПараметра - Строка
//  УстановленныеПараметры - Массив из Строка
//
Процедура УстановкаПараметровСеанса(Знач ИмяПараметра, УстановленныеПараметры) Экспорт
	Если ИмяПараметра = "ИнтерактивнаяПроверкаЗаполненияКонтактнойИнформации" Тогда
		ПараметрыСеанса.ИнтерактивнаяПроверкаЗаполненияКонтактнойИнформации = Ложь;
		УстановленныеПараметры.Добавить("ИнтерактивнаяПроверкаЗаполненияКонтактнойИнформации");
	КонецЕсли;
КонецПроцедуры

Процедура УстановитьИспользованиеРегламентногоЗадания(Статус) Экспорт
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		МодульРаботаСАдресами.УстановитьСостояниеРегламентногоЗадания(Статус);
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбщиеСлужебныеПроцедурыИФункции

Функция СобытиеЖурналаРегистрации() Экспорт
	
	Возврат НСтр("ru = 'Контактная информация'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

Функция КонтактнаяИнформацияПоПредставлению(Представление, ОжидаемыйВид, РазбиватьНаПоля = Ложь) Экспорт
	
	ОжидаемыйТип = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ТипВидаКонтактнойИнформации(ОжидаемыйВид);
	
	Если ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		
		Возврат СформироватьАдресПоПредставлению(Представление, РазбиватьНаПоля);
		
	ИначеЕсли ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Телефон
		ИЛИ ОжидаемыйТип = Перечисления.ТипыКонтактнойИнформации.Факс Тогда
			Возврат ДесериализацияТелефонаФаксаВJSON("", Представление, ОжидаемыйТип);
		
	Иначе
		
		КонтактнаяИнформация = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеНовойКонтактнойИнформации(ОжидаемыйТип);
		КонтактнаяИнформация.Value = Представление;
		Возврат КонтактнаяИнформация;
		
	КонецЕсли;
	
КонецФункции

Функция СформироватьАдресПоПредставлению(Представление, РазбиватьНаПоля = Ложь)
	
	ЕстьРаботаСАдресамиКлиентСервер = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами();
	
	Если ЕстьРаботаСАдресамиКлиентСервер Тогда
		МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
		Адрес = МодульРаботаСАдресамиКлиентСервер.ОписаниеНовойКонтактнойИнформации(Перечисления.ТипыКонтактнойИнформации.Адрес);
		НаименованиеОсновнаяСтрана = СокрЛП(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(МодульРаботаСАдресамиКлиентСервер.ОсновнаяСтрана(), "Наименование"));
	Иначе
		Адрес = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеНовойКонтактнойИнформации(Перечисления.ТипыКонтактнойИнформации.Адрес);
		НаименованиеОсновнаяСтрана = "";
	КонецЕсли;
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		Адрес.Value = Представление;
		Возврат Адрес;
	КонецЕсли;
	
	ДанныеАнализа = ЧастиАдресаТаблицей(Представление);
	Если ДанныеАнализа.Количество() = 0 Тогда
		Адрес.Value = Представление;
		Возврат Адрес;
	КонецЕсли;
	
	ОпределитьСтрануИИндекс(ДанныеАнализа);
	СтрокаСтраны = ДанныеАнализа.Найти(-2, "Уровень");
	
	Если СтрокаСтраны = Неопределено Тогда
		Адрес.Country = НаименованиеОсновнаяСтрана;
	Иначе
		Адрес.Country = СокрЛП(ВРег(СтрокаСтраны.Значение));
	КонецЕсли;
	
	ДанныеОСтране = УправлениеКонтактнойИнформацией.ДанныеСтраныМира(, Адрес.Country);
	Если ДанныеОСтране <> Неопределено Тогда
		Адрес.countryCode = ДанныеОСтране.Код;
	КонецЕсли;
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		МодульРаботаСАдресами.ОбработкаЧастыхСокращенийВАдресах(ДанныеАнализа);
	КонецЕсли;
	
	Если Адрес.Country = НаименованиеОсновнаяСтрана Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
			
			МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
			ВариантыАдреса = МодульАдресныйКлассификаторСлужебный.РаспознатьАдрес(ДанныеАнализа, Представление, РазбиватьНаПоля);
			
			Если ВариантыАдреса = Неопределено Тогда
				
				Если РазбиватьНаПоля Тогда
					
					МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
					Если  МодульРаботаСАдресамиКлиентСервер <> Неопределено Тогда
						Адрес.AddressType = МодульРаботаСАдресамиКлиентСервер.МуниципальныйАдрес();
					КонецЕсли;
					
					Адрес.Value = Представление;
					РаспределитьАдресПоПолямБезКлассификатора(Адрес, ДанныеАнализа);
					
				Иначе
					
					Адрес.Value = Представление;
					Адрес.AddressType = УправлениеКонтактнойИнформациейКлиентСервер.АдресВСвободнойФорме();
					
				КонецЕсли;
			Иначе
				
				ЗаполнитьЗначенияСвойств(Адрес, ВариантыАдреса);
				Если ЕстьРаботаСАдресамиКлиентСервер Тогда
					МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
					Если МодульРаботаСАдресамиКлиентСервер <> Неопределено Тогда
						МодульРаботаСАдресамиКлиентСервер.ОбновитьПредставлениеАдреса(Адрес, Ложь);
					КонецЕсли;
				Иначе
					ОбновитьПредставлениеАдреса(Адрес, Ложь);
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе
		
		Если ЕстьРаботаСАдресамиКлиентСервер Тогда
			ТипАдреса = ?(УправлениеКонтактнойИнформацией.ЭтоСтранаУчастникЕАЭС(Адрес.Country),
				УправлениеКонтактнойИнформациейКлиентСервер.АдресЕАЭС(),
				УправлениеКонтактнойИнформациейКлиентСервер.ИностранныйАдрес());
			Адрес.AddressType = ТипАдреса;
		Иначе
			Адрес.AddressType = УправлениеКонтактнойИнформациейКлиентСервер.АдресВСвободнойФорме();
		КонецЕсли;
		
		НовоеПредставление = Новый Массив;
		ДанныеАнализа.Сортировать("Позиция");
		Для каждого ЧастьАдрес Из ДанныеАнализа Цикл
			Если ЧастьАдрес.Уровень >=0 Тогда
				НовоеПредставление.Добавить(ЧастьАдрес.Значение);
			КонецЕсли;
		КонецЦикла;
		
		Адрес.value = СтрСоединить(НовоеПредставление, ", ");
		Адрес.street = Адрес.value;
		
	КонецЕсли;
	
	Если ПустаяСтрока(Адрес.ZipCode) И Адрес.AddressType <> УправлениеКонтактнойИнформациейКлиентСервер.АдресВСвободнойФорме() Тогда
		СтрокаИндекс = ДанныеАнализа.Найти(-1, "Уровень");
		Если СтрокаИндекс <> Неопределено Тогда
			Адрес.ZipCode = СокрЛП(СтрокаИндекс.Значение);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Адрес;
	
КонецФункции

Процедура ОбновитьПредставлениеАдреса(Адрес, ВключатьСтрануВПредставление)
	
	Если ТипЗнч(Адрес) <> Тип("Структура") Тогда
		ВызватьИсключение НСтр("ru = 'Для формирования представления адреса передан некорректный тип адреса'");
	КонецЕсли;
	
	СписокЗаполненныхУровней = Новый Массив;
	
	Если ВключатьСтрануВПредставление И Адрес.Свойство("country") И НЕ ПустаяСтрока(Адрес.Country) Тогда
		СписокЗаполненныхУровней.Добавить(Адрес.Country);
	КонецЕсли;
	
	Если Адрес.Свойство("zipCode") И НЕ ПустаяСтрока(Адрес.ZipCode) Тогда
		СписокЗаполненныхУровней.Добавить(Адрес.ZipCode);
	КонецЕсли;
	
	СписокЗаполненныхУровней.Добавить(СокрЛП(Адрес["area"] + " " + Адрес["areaType"]));
	СписокЗаполненныхУровней.Добавить(СокрЛП(Адрес["city"] + " " + Адрес["cityType"]));
	
	Адрес.Value = СтрСоединить(СписокЗаполненныхУровней, ", ");
	
КонецПроцедуры

Процедура РаспределитьАдресПоПолямБезКлассификатора(Адрес, ДанныеАнализа)
	
	ПредставлениеПоДаннымАнализа = Новый Массив;
	
	Для каждого ЧастьАдрес Из ДанныеАнализа Цикл
		Если ЧастьАдрес.Уровень >= 0 Тогда
			
			Если ЧастьАдрес.Уровень = 1 Тогда
				Адрес.areaValue = ЧастьАдрес.Значение;
				Адрес.area      = ЧастьАдрес.Наименование;
				Адрес.areaType  = ЧастьАдрес.ТипОбъекта;
				Адрес.munLevels.Добавить("area");
				Адрес.admLevels.Добавить("area");
			Иначе
				ПредставлениеПоДаннымАнализа.Добавить(
					УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(
					ЧастьАдрес.Наименование, ЧастьАдрес.ТипОбъекта));
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Адрес.street = СтрСоединить(ПредставлениеПоДаннымАнализа, ", ");
	Адрес.munLevels.Добавить("street");
	Адрес.admLevels.Добавить("street");
	
КонецПроцедуры

Функция ЧастиАдресаТаблицей(Знач Текст)
	
	ТипыАдресныхОбъектов = ТипыАдресныхОбъектов();
	Результат            = ЧастиАдреса();
	КодРегиона           = Неопределено;
	
	Номер = 1;
	Для Каждого Часть Из СловаТекстаТаблицей(Текст, "," + Символы.ПС) Цикл
		Значение = СокрЛП(Часть.Значение);
		Если ПустаяСтрока(Значение) Тогда
			Продолжить;
		КонецЕсли;
		
		Строка = Результат.Добавить();
		
		Строка.Уровень = 0;
		Строка.Позиция = Номер;
		Номер = Номер + 1;
		
		Строка.Начало = Часть.Начало;
		Строка.Длина  = Часть.Длина;
		  
		Если СтрНайти(Значение, " ") = 0 Тогда 
			Строка.Наименование = Значение;
			Строка.Значение = Строка.Наименование;
			Продолжить;
		КонецЕсли;
		
		ЗначениеВерхнийРегистр = ВРег(Значение);
		Для Каждого ТипАдресныхОбъектов Из ТипыАдресныхОбъектов Цикл
			
			Если СтрНачинаетсяС(ЗначениеВерхнийРегистр, ТипАдресныхОбъектов.ТипОбъектаВНачале) Тогда
				
				Строка.Наименование = СокрЛП(Сред(Значение, ТипАдресныхОбъектов.Длина + 1));
				Строка.ТипОбъекта   = СокрЛП(Лев(Значение, ТипАдресныхОбъектов.Длина));
				Строка.Значение     = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(Строка.Наименование, Строка.ТипОбъекта);
				Прервать;
				
			ИначеЕсли СтрЗаканчиваетсяНа(ЗначениеВерхнийРегистр, ТипАдресныхОбъектов.ТипОбъектаВКонце) Тогда
				
				Строка.Наименование = СокрЛП(Сред(Значение, 1, СтрДлина(Значение) - ТипАдресныхОбъектов.Длина));
				Строка.ТипОбъекта   = СокрЛП(Прав(Значение, ТипАдресныхОбъектов.Длина));
				Строка.Значение     = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(Строка.Наименование, Строка.ТипОбъекта);
				Прервать;
				
			КонецЕсли;
			
		КонецЦикла;
		
		// Локализация
		Если КодРегиона = Неопределено И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда			
			
			МодульАдресныйКлассификатор = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификатор");
			КодРегиона = МодульАдресныйКлассификатор.КодРегионаПоНаименованию(
				УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(Строка.Наименование, Строка.ТипОбъекта, Истина));
			
			Если КодРегиона = Неопределено И ЗначениеЗаполнено(Значение) Тогда
				КодРегиона = МодульАдресныйКлассификатор.КодРегионаПоНаименованию(Значение);
			КонецЕсли;
				
				
			Если КодРегиона <> Неопределено Тогда
				Строка.Значение = МодульАдресныйКлассификатор.НаименованиеРегионаПоКоду(КодРегиона);
				Строка.Уровень  = 1;
			КонецЕсли;
		КонецЕсли;
		// Конец Локализация
		
		Если ЗначениеЗаполнено(Строка.Значение) Тогда
			Продолжить;
		КонецЕсли;
		
		ЧастиАдресногоОбъекта = СтрРазделить(Значение, " " + Символы.ПС + Символы.Таб);
	
		Строка.ТипОбъекта   = ЧастиАдресногоОбъекта[0];
		ЧастиАдресногоОбъекта.Удалить(0);
		Строка.Наименование = СокрЛП(СтрСоединить(ЧастиАдресногоОбъекта, " "));
		Строка.Значение = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(Строка.Наименование, Строка.ТипОбъекта);
	
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Сокращение - Строка
//    * Длина - Число 
//    * СокращениеВНачале - Строка
//    * СокращениеВКонце - Строка
//
Функция ТипыАдресныхОбъектов()

	// Локализация
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда			
		МодульАдресныйКлассификаторПовтИсп = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторПовтИсп");
		Возврат МодульАдресныйКлассификаторПовтИсп.ТипыАдресныхОбъектовДляРаспознаванияАдреса();
	КонецЕсли;
	// Конец Локализация
	
	СписокСокращений = Новый ТаблицаЗначений();
	СписокСокращений.Колонки.Добавить("ТипОбъекта",        ОбщегоНазначения.ОписаниеТипаСтрока(50));
	СписокСокращений.Колонки.Добавить("Длина",             ОбщегоНазначения.ОписаниеТипаЧисло(3));
	СписокСокращений.Колонки.Добавить("ТипОбъектаВНачале", ОбщегоНазначения.ОписаниеТипаСтрока(20));
	СписокСокращений.Колонки.Добавить("ТипОбъектаВКонце",  ОбщегоНазначения.ОписаниеТипаСтрока(20));

	Возврат СписокСокращений;
	
КонецФункции

// Функция-конструктор таблицы содержащей адрес, где каждая строка это часть адреса.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Уровень - Число
//    * Позиция - Число
//    * Значение - Строка
//    * Наименование - Строка
//    * ТипОбъекта - Строка
//    * Начало - Число
//    * Длина - Число
//    * Идентификатор - Строка
// 
Функция ЧастиАдреса() Экспорт
	
	ТипСтрока = Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(128));
	ТипЧисло  = Новый ОписаниеТипов("Число");
	
	Результат = Новый ТаблицаЗначений;
	Колонки = Результат.Колонки;
	Колонки.Добавить("Уровень", ТипЧисло);
	Колонки.Добавить("Позиция", ТипЧисло);
	Колонки.Добавить("Значение", ТипСтрока);
	Колонки.Добавить("Наименование", ТипСтрока);
	Колонки.Добавить("ТипОбъекта", ТипСтрока);
	Колонки.Добавить("Начало", ТипЧисло);
	Колонки.Добавить("Длина", ТипЧисло);
	Колонки.Добавить("Идентификатор", ТипСтрока);
	Возврат Результат;
	
КонецФункции

Функция СловаТекстаТаблицей(Знач Текст, Знач Разделители = Неопределено)
	
	// Удаление из текста спец. символов "точек", "номеров".
	Текст = СтрЗаменить(Текст, "№", "");
	
	НачалоСлова = 0;
	Состояние   = 0;
	
	Результат = ТаблицаФрагментов();
	
	Для Позиция = 1 По СтрДлина(Текст) Цикл
		ТекущийСимвол = Сред(Текст, Позиция, 1);
		ЭтоРазделитель = ?(Разделители = Неопределено, ПустаяСтрока(ТекущийСимвол), СтрНайти(Разделители, ТекущийСимвол) > 0);
		
		Если Состояние = 0 И (Не ЭтоРазделитель) Тогда
			НачалоСлова = Позиция;
			Состояние   = 1;
		ИначеЕсли Состояние = 1 И ЭтоРазделитель Тогда
			Строка = Результат.Добавить();
			Строка.Начало = НачалоСлова;
			Строка.Длина  = Позиция-НачалоСлова;
			Строка.Значение = Сред(Текст, Строка.Начало, Строка.Длина);
			Состояние = 0;
		КонецЕсли;
	КонецЦикла;
	
	Если Состояние = 1 Тогда
		Строка = Результат.Добавить();
		Строка.Начало = НачалоСлова;
		Строка.Длина  = Позиция-НачалоСлова;
		Строка.Значение = Сред(Текст, Строка.Начало, Строка.Длина)
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Функция-конструктор таблицы фрагментов
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//    * Значение - Строка
//    * Начало - Число
//    * Длина - Число
//
Функция ТаблицаФрагментов()
		
	ТипСтрока = Новый ОписаниеТипов("Строка");
	ТипЧисло  = Новый ОписаниеТипов("Число");
	
	Результат = Новый ТаблицаЗначений;
	Колонки = Результат.Колонки;
	Колонки.Добавить("Значение", ТипСтрока);
	Колонки.Добавить("Начало",   ТипЧисло);
	Колонки.Добавить("Длина",    ТипЧисло);
	
	Возврат Результат;
	
КонецФункции

Процедура ОпределитьСтрануИИндекс(ДанныеАдреса)
	
	Если Не УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		Возврат;
	КонецЕсли;
	
	ОписаниеТипаЧисло = Новый ОписаниеТипов("Число");
	МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
	Классификатор = МодульРаботаСАдресами.ТаблицаКлассификатора();
	
	Для каждого ЭлементАдреса Из ДанныеАдреса Цикл
		Индекс = ОписаниеТипаЧисло.ПривестиЗначение(ЭлементАдреса.Наименование);
		Если Индекс >= 100000 И Индекс < 1000000 Тогда
			ЭлементАдреса.Уровень = -1;
		Иначе
			Если Классификатор.Найти(ВРег(ЭлементАдреса.Значение), "Наименование") <> Неопределено Тогда
				ЭлементАдреса.Уровень = -2;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры


Функция ПредставлениеКонтактнойИнформации(Знач КонтактнаяИнформация) Экспорт
	
	Если ПустаяСтрока(КонтактнаяИнформация) Тогда
		Возврат "";
	КонецЕсли;
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(КонтактнаяИнформация) Тогда
		
		КонтактнаяИнформация = JSONВКонтактнуюИнформациюПоПолям(КонтактнаяИнформация, Неопределено);
		
	ИначеЕсли ТипЗнч(КонтактнаяИнформация) = Тип("Структура") Тогда
		
		Если КонтактнаяИнформация.Свойство("НомерТелефона") Тогда
			ТипКонтактнойИнформации =Перечисления.ТипыКонтактнойИнформации.Телефон;
		Иначе
			ТипКонтактнойИнформации =Перечисления.ТипыКонтактнойИнформации.Адрес;
		КонецЕсли;
		
		КонтактнаяИнформация = КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация, ТипКонтактнойИнформации);
		
	ИначеЕсли ТипЗнч(КонтактнаяИнформация) = Тип("Строка") Или ТипЗнч(КонтактнаяИнформация) = Тип("ОбъектXDTO") Тогда
		
		КонтактнаяИнформация = КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация);
		
	КонецЕсли;
	
	Если ПустаяСтрока(КонтактнаяИнформация.Value) Тогда
		СформироватьПредставлениеКонтактнойИнформации(КонтактнаяИнформация, Неопределено);
	КонецЕсли;
	
	Возврат КонтактнаяИнформация.Value
	
КонецФункции

Функция АдресВведенВСвободнойФорме(Знач КонтактнаяИнформация) Экспорт
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(КонтактнаяИнформация) Тогда
		КонтактнаяИнформацияJSON = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(КонтактнаяИнформация);
		КонтактнаяИнформация = JSONВКонтактнуюИнформациюПоПолям(КонтактнаяИнформацияJSON, Перечисления.ТипыКонтактнойИнформации.Адрес);
	ИначеЕсли УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(КонтактнаяИнформация) Тогда
		КонтактнаяИнформация = JSONВКонтактнуюИнформациюПоПолям(КонтактнаяИнформация, Перечисления.ТипыКонтактнойИнформации.Адрес);
	КонецЕсли;
	
	Если ТипЗнч(КонтактнаяИнформация) = Тип("Структура")
		И КонтактнаяИнформация.Свойство("AddressType") Тогда
			Возврат УправлениеКонтактнойИнформациейКлиентСервер.ЭтоАдресВСвободнойФорме(КонтактнаяИнформация.AddressType);
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция СформироватьПредставлениеКонтактнойИнформации(Знач Информация, Знач ВидИнформации)
	
	Если ТипЗнч(Информация) = Тип("Строка") И УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(Информация) Тогда
		ТипКонтактнойИнформации = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ВидИнформации, "Тип");
		Информация = JSONВКонтактнуюИнформациюПоПолям(Информация, ТипКонтактнойИнформации);
	КонецЕсли;
	
	Если ТипЗнч(Информация) = Тип("Структура") Тогда
		
		Если ЭтоТипАдрес(Информация.Type) Тогда
			Возврат ПредставлениеАдреса(Информация, ВидИнформации);
			
		ИначеЕсли Информация.Type = Строка(Перечисления.ТипыКонтактнойИнформации.Телефон)
			ИЛИ Информация.Type = Строка(Перечисления.ТипыКонтактнойИнформации.Факс) Тогда
			ПредставлениеТелефона = ПредставлениеТелефона(Информация);
			Возврат ?(ПустаяСтрока(ПредставлениеТелефона), Информация.Value, ПредставлениеТелефона);
		КонецЕсли;
		
		Возврат Информация.Value;
	КонецЕсли;
	
	Возврат СформироватьПредставлениеКонтактнойИнформации(КонтактнаяИнформацияВСтруктуруJSON(Информация), ВидИнформации);
	
КонецФункции

Функция ЭтоНациональныйАдрес(Знач Адрес) Экспорт
	
	Если НЕ ЗначениеЗаполнено(Адрес) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		
		Если ТипЗнч(Адрес) = Тип("Строка") Тогда
			Адрес = JSONВКонтактнуюИнформациюПоПолям(Адрес, Перечисления.ТипыКонтактнойИнформации.Адрес);
		КонецЕсли;
		
		Если ТипЗнч(Адрес) = Тип("Структура") И Адрес.Свойство("Country")Тогда
			
			МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
			НаименованиеСтраны = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(МодульРаботаСАдресамиКлиентСервер.ОсновнаяСтрана(), "Наименование");
			Возврат СтрСравнить(НаименованиеСтраны, Адрес.Country) = 0;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ПредставлениеАдреса(Знач Адрес, Знач ВидИнформации)
	
	Если ТипЗнч(ВидИнформации) = Тип("Структура") И ВидИнформации.Свойство("ВключатьСтрануВПредставление") Тогда
		ВключатьСтрануВПредставление = ВидИнформации.ВключатьСтрануВПредставление;
	Иначе
		ВключатьСтрануВПредставление = Ложь;
	КонецЕсли;
	
	Если ТипЗнч(Адрес) = Тип("Структура") Тогда
		
		Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
			МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
			МодульРаботаСАдресамиКлиентСервер.ОбновитьПредставлениеАдреса(Адрес, ВключатьСтрануВПредставление);
		Иначе
			ОбновитьПредставлениеАдреса(Адрес, ВключатьСтрануВПредставление);
		КонецЕсли;
		
		Возврат Адрес.Value;
	Иначе
		Представление = СокрЛП(Адрес);
		
		Если СтрЧислоВхождений(Представление, ",") = 9 Тогда
			ПредставлениеМассивом = СтрРазделить(Представление, ",", Ложь);
			Если ПредставлениеМассивом.Количество() > 0 Тогда
				Для Индекс = 0 По ПредставлениеМассивом.ВГраница() Цикл
					ПредставлениеМассивом[Индекс] = СокрЛП(ПредставлениеМассивом[Индекс]);
				КонецЦикла;
				ПредставлениеМассивом.Удалить(0); // удаляем страну
				Представление = СтрСоединить(ПредставлениеМассивом, ", ");
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Представление;
	
КонецФункции

Функция ПредставлениеТелефона(ДанныеТелефон) Экспорт
	
	Если ТипЗнч(ДанныеТелефон) = Тип("Структура") Тогда
		
		ПредставлениеТелефона = УправлениеКонтактнойИнформациейКлиентСервер.СформироватьПредставлениеТелефона(
			СократитьНеЦифры(ДанныеТелефон.countryCode),
			ДанныеТелефон.areaCode,
			ДанныеТелефон.number,
			ДанныеТелефон.extNumber,
			"");
			
	Иначе
		
		ПредставлениеТелефона = УправлениеКонтактнойИнформациейКлиентСервер.СформироватьПредставлениеТелефона(
			СократитьНеЦифры(ДанныеТелефон.КодСтраны), 
			ДанныеТелефон.КодГорода,
			ДанныеТелефон.Номер,
			ДанныеТелефон.Добавочный,
			"");
		
	КонецЕсли;
	
	Возврат ПредставлениеТелефона;
	
КонецФункции

// Параметры:
//  Источник - СправочникСсылка.ВидыКонтактнойИнформации
//           - Структура
//           - Неопределено
// Возвращаемое значение:
//  Структура:
//    * Ссылка - СправочникСсылка.ВидыКонтактнойИнформации
//             - Неопределено
//    * Ошибка - Булево
//    * ОписаниеОшибки - Строка
// 
Функция СтруктураВидаКонтактнойИнформации(Знач Источник = Неопределено) Экспорт
	
	МетаданныеРеквизитов = Метаданные.Справочники.ВидыКонтактнойИнформации.Реквизиты;
	
	Если ТипЗнч(Источник) = Тип("СправочникСсылка.ВидыКонтактнойИнформации") Тогда
		Реквизиты = "Наименование";
		Для Каждого МетаданныеРеквизита Из МетаданныеРеквизитов Цикл
			Реквизиты = Реквизиты + "," + МетаданныеРеквизита.Имя;
		КонецЦикла;
		
		Результат = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник, Реквизиты);
	Иначе
		Результат = Новый Структура("Наименование", "");
		Для Каждого МетаданныеРеквизита Из МетаданныеРеквизитов Цикл
			Результат.Вставить(МетаданныеРеквизита.Имя, МетаданныеРеквизита.Тип.ПривестиЗначение());
		КонецЦикла;
		
		Если Источник <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(Результат, Источник);
			
			Если Источник.Свойство("НастройкиПроверки") И Источник.НастройкиПроверки <> Неопределено Тогда
				ЗаполнитьЗначенияСвойств(Результат, Источник.НастройкиПроверки);
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	Результат.Вставить("Ссылка", Источник);
	
	Возврат Результат;
	
КонецФункции

Функция ДанныеВидовКонтактнойИнформации(Знач ВидыКонтактнойИнформации) Экспорт
	
	МетаданныеРеквизитов = Метаданные.Справочники.ВидыКонтактнойИнформации.Реквизиты;
	Реквизиты = "Наименование, ИмяПредопределенныхДанных, ПометкаУдаления";
	Для Каждого МетаданныеРеквизита Из МетаданныеРеквизитов Цикл
		Реквизиты = Реквизиты + "," + МетаданныеРеквизита.Имя;
	КонецЦикла;
	
	Возврат ОбщегоНазначения.ЗначенияРеквизитовОбъектов(ВидыКонтактнойИнформации, Реквизиты);
	
КонецФункции

// Параметры:
//   Объект - СправочникОбъект
///
Процедура ОбновитьКонтактнуюИнформациюДляСписковДляОбъекта(Объект) Экспорт
	
	КонтактнаяИнформация = Объект.КонтактнаяИнформация;
	
	Если КонтактнаяИнформация.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Индекс = КонтактнаяИнформация.Количество() - 1;
	Пока Индекс >= 0 Цикл
		Если НЕ ЗначениеЗаполнено(КонтактнаяИнформация[Индекс].Вид) Тогда
			КонтактнаяИнформация.Удалить(Индекс);
		КонецЕсли;
		Индекс = Индекс -1;
	КонецЦикла;
	
	КолонкаДействуетСОтсутствует = Не УправлениеКонтактнойИнформациейСлужебныйПовтИсп.КонтактнаяИнформацияОбъектаСодержитКолонкуДействуетС(Объект.Ссылка);
	
	Запрос = Новый Запрос("ВЫБРАТЬ
		|	КонтактнаяИнформация.Представление КАК Представление,
		|	КонтактнаяИнформация.НомерСтроки КАК НомерСтроки,
		|	КонтактнаяИнформация.Вид КАК Вид" + ?(КолонкаДействуетСОтсутствует, "", ", КонтактнаяИнформация.ДействуетС КАК ДействуетС") + "
		|ПОМЕСТИТЬ КонтактнаяИнформация
		|ИЗ
		|	&КонтактнаяИнформация КАК КонтактнаяИнформация
		|;");//@query-part
	
	Если КолонкаДействуетСОтсутствует Тогда
		Запрос.Текст = Запрос.Текст + "ВЫБРАТЬ
		|	КонтактнаяИнформация.Представление КАК Представление,
		|	КонтактнаяИнформация.Вид КАК Вид,
		|	КонтактнаяИнформация.НомерСтроки КАК НомерСтроки,
		|	КОЛИЧЕСТВО(КонтактнаяИнформация.Вид) КАК Количество
		|ИЗ
		|	КонтактнаяИнформация КАК КонтактнаяИнформация
		|
		|СГРУППИРОВАТЬ ПО
		|	КонтактнаяИнформация.Вид,
		|	КонтактнаяИнформация.НомерСтроки,
		|	КонтактнаяИнформация.Представление
		|УПОРЯДОЧИТЬ ПО
		|	НомерСтроки
		|ИТОГИ ПО
		|	Вид";
	Иначе
		Запрос.Текст = Запрос.Текст + "ВЫБРАТЬ
		|	КонтактнаяИнформация.Вид КАК Вид,
		|	МАКСИМУМ(КонтактнаяИнформация.ДействуетС) КАК ДействуетС
		|ПОМЕСТИТЬ АктуальнаяКонтактнаяИнформация
		|ИЗ
		|	КонтактнаяИнформация КАК КонтактнаяИнформация
		|
		|СГРУППИРОВАТЬ ПО
		|	КонтактнаяИнформация.Вид
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	КонтактнаяИнформация.Представление КАК Представление,
		|	КонтактнаяИнформация.Вид КАК Вид,
		|	КонтактнаяИнформация.ДействуетС КАК ДействуетС,
		|	ЕСТЬNULL(КонтактнаяИнформация.НомерСтроки, 0) КАК НомерСтроки,
		|	КОЛИЧЕСТВО(КонтактнаяИнформация.Вид) КАК Количество
		|ИЗ
		|	АктуальнаяКонтактнаяИнформация КАК АктуальнаяКонтактнаяИнформация
		|		ЛЕВОЕ СОЕДИНЕНИЕ КонтактнаяИнформация КАК КонтактнаяИнформация
		|		ПО АктуальнаяКонтактнаяИнформация.ДействуетС = КонтактнаяИнформация.ДействуетС
		|			И АктуальнаяКонтактнаяИнформация.Вид = КонтактнаяИнформация.Вид
		|
		|СГРУППИРОВАТЬ ПО
		|	КонтактнаяИнформация.Вид,
		|	КонтактнаяИнформация.Представление,
		|	КонтактнаяИнформация.ДействуетС,
		|	КонтактнаяИнформация.НомерСтроки
		|УПОРЯДОЧИТЬ ПО
		|	НомерСтроки
		|ИТОГИ ПО
		|	Вид, ДействуетС";
	КонецЕсли;
	
	Запрос.УстановитьПараметр("КонтактнаяИнформация", КонтактнаяИнформация.Выгрузить());
	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаВид       = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	Пока ВыборкаВид.Следующий() Цикл
		ВыборкаДетальныеЗаписи = ВыборкаВид.Выбрать();
		Если ВыборкаВид.Количество = 1 Тогда
			Если КолонкаДействуетСОтсутствует Тогда
				СтрокаТаблиц = КонтактнаяИнформация.Найти(ВыборкаВид.Вид, "Вид");
				СтрокаТаблиц.ВидДляСписка = ВыборкаВид.Вид;
			Иначе
				ДействуетС = Дата(1,1,1);
				Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
					Если ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.ДействуетС) Тогда
						ДействуетС = ВыборкаДетальныеЗаписи.ДействуетС;
					КонецЕсли;
				КонецЦикла;
				НайденныеСтроки = КонтактнаяИнформация.НайтиСтроки(Новый Структура("Вид", ВыборкаВид.Вид));
				Для каждого СтрокаСКонтактнойИнформацией Из НайденныеСтроки Цикл
					СтрокаСКонтактнойИнформацией.ВидДляСписка = ?(СтрокаСКонтактнойИнформацией.ДействуетС = ДействуетС,
							ВыборкаВид.Вид, Справочники.ВидыКонтактнойИнформации.ПустаяСсылка());
				КонецЦикла;
			КонецЕсли;
		ИначеЕсли ВыборкаВид.Количество > 1 Тогда
			НайденныеСтроки = КонтактнаяИнформация.НайтиСтроки(Новый Структура("Вид", ВыборкаВид.Вид));
			Для каждого СтрокаСКонтактнойИнформацией Из НайденныеСтроки Цикл
				СтрокаСКонтактнойИнформацией.ВидДляСписка = Неопределено;
			КонецЦикла;

			ЭлементыКонтактнойИнформации = Новый Массив;
			Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
				Если ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Представление) Тогда
					ЭлементыКонтактнойИнформации.Добавить(ВыборкаДетальныеЗаписи.Представление);
				КонецЕсли;
			КонецЦикла;
			СтрокаТаблиц               = КонтактнаяИнформация.Добавить();
			СтрокаТаблиц.ВидДляСписка  = ВыборкаВид.Вид;
			СтрокаТаблиц.Представление = СтрСоединить(ЭлементыКонтактнойИнформации, ", ");
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Процедура ОбновитьКонтактнуюИнформациюДляСписков() Экспорт
	
	ОбъектыСКолонкойВидДляСписка = ОбъектыСодержащиеВидДляСписка();
	
	Для каждого ОбъектСсылка Из ОбъектыСКолонкойВидДляСписка Цикл
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить(Метаданные.НайтиПоТипу(ТипЗнч(ОбъектСсылка)).ПолноеИмя());
		ЭлементБлокировки.УстановитьЗначение("Ссылка", ОбъектСсылка);
		
		НачатьТранзакцию();
		Попытка
			
			Блокировка.Заблокировать();
		
			Объект = ОбъектСсылка.ПолучитьОбъект();
			КонтактнаяИнформация = Объект.КонтактнаяИнформация;
			
			Отбор = Новый Структура("Тип", Перечисления.ТипыКонтактнойИнформации.ПустаяСсылка());
			СтрокиДляУдаления = КонтактнаяИнформация.НайтиСтроки(Отбор);
			Для каждого СтрокаДляУдаления Из СтрокиДляУдаления Цикл
				КонтактнаяИнформация.Удалить(СтрокаДляУдаления);
			КонецЦикла;
			
			Запрос = Новый Запрос;
			Запрос.Текст = 
				"ВЫБРАТЬ
				|	КонтактнаяИнформация.Представление КАК Представление,
				|	КонтактнаяИнформация.Вид КАК Вид
				|ПОМЕСТИТЬ КонтактнаяИнформация
				|ИЗ
				|	&КонтактнаяИнформация КАК КонтактнаяИнформация
				|;
				|
				|////////////////////////////////////////////////////////////////////////////////
				|ВЫБРАТЬ
				|	КонтактнаяИнформация.Представление КАК Представление,
				|	КонтактнаяИнформация.Вид КАК Вид,
				|	КОЛИЧЕСТВО(КонтактнаяИнформация.Вид) КАК Количество
				|ИЗ
				|	КонтактнаяИнформация КАК КонтактнаяИнформация
				|
				|СГРУППИРОВАТЬ ПО
				|	КонтактнаяИнформация.Вид,
				|	КонтактнаяИнформация.Представление ИТОГИ ПО Вид";
			
			Запрос.УстановитьПараметр("КонтактнаяИнформация", КонтактнаяИнформация);
			РезультатЗапроса = Запрос.Выполнить(); // @skip-check query-in-loop - Запросы к разным таблицам.
			ВыборкаВид = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
			
			Пока ВыборкаВид.Следующий() Цикл
				ВыборкаДетальныеЗаписи = ВыборкаВид.Выбрать();
				Если ВыборкаВид.Количество = 1 Тогда
					СтрокаТаблиц = КонтактнаяИнформация.Найти(ВыборкаВид.Вид, "Вид");
					СтрокаТаблиц.ВидДляСписка = ВыборкаВид.Вид;
				ИначеЕсли ВыборкаВид.Количество > 1 Тогда
					СтрокаТаблиц = КонтактнаяИнформация.Добавить();
					СтрокаТаблиц.ВидДляСписка = ВыборкаВид.Вид;
					Разделитель   = "";
					Представление = "";
					Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
						Представление = Представление +Разделитель + ВыборкаДетальныеЗаписи.Представление;
						Разделитель = ", ";
					КонецЦикла;
					СтрокаТаблиц.Представление = Представление;
				КонецЕсли;
			КонецЦикла;
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект);
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
		КонецПопытки;
		
	КонецЦикла;

КонецПроцедуры

Функция ОбъектыСодержащиеВидДляСписка()
	
	ОбъектыМетаданных = Новый Массив; // Массив из СправочникСсылка, ДокументСсылка
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ВидыКонтактнойИнформации.Ссылка,
	|ВЫБОР
	|	КОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида <> """"
	|	ТОГДА ВидыКонтактнойИнформации.ИмяПредопределенногоВида
	|	ИНАЧЕ ВидыКонтактнойИнформации.ИмяПредопределенныхДанных
	|КОНЕЦ КАК ИмяПредопределенногоВида
	|ИЗ
	|	Справочник.ВидыКонтактнойИнформации КАК ВидыКонтактнойИнформации
	|ГДЕ
	|	ВидыКонтактнойИнформации.ЭтоГруппа = ИСТИНА";
	
	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		Если СтрНачинаетсяС(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, "Справочник") Тогда
			ИмяОбъекта = Сред(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, СтрДлина("Справочник") + 1);
			Если Метаданные.Справочники.Найти(ИмяОбъекта) <> Неопределено Тогда 
				КонтактнаяИнформация = Метаданные.Справочники[ИмяОбъекта].ТабличныеЧасти.КонтактнаяИнформация;
				Если КонтактнаяИнформация.Реквизиты.Найти("ВидДляСписка") <> Неопределено Тогда
					ОбъектыМетаданных.Добавить(Справочники[ИмяОбъекта].ПустаяСсылка());
				КонецЕсли;
			КонецЕсли;
		ИначеЕсли СтрНачинаетсяС(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, "Документ") Тогда
			ИмяОбъекта = Сред(ВыборкаДетальныеЗаписи.ИмяПредопределенногоВида, СтрДлина("Документ") + 1);
			Если Метаданные.Документы.Найти(ИмяОбъекта) <> Неопределено Тогда
				КонтактнаяИнформация = Метаданные.Документы[ИмяОбъекта].ТабличныеЧасти.КонтактнаяИнформация;
				Если КонтактнаяИнформация.Реквизиты.Найти("ВидДляСписка") <> Неопределено Тогда
					ОбъектыМетаданных.Добавить(Документы[ИмяОбъекта].ПустаяСсылка());
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	НаборТекстаЗапроса = Новый Массив;
	ШаблонЗапроса = "ВЫБРАТЬ
		|	КонтактнаяИнформация.Ссылка КАК Ссылка
		|ИЗ
		|	#КонтактнаяИнформацияОбъектаМетаданных КАК КонтактнаяИнформация
		|ГДЕ
		|	КонтактнаяИнформация.Вид <> ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ПустаяСсылка)
		|
		|СГРУППИРОВАТЬ ПО
		|	КонтактнаяИнформация.Ссылка
		|
		|ИМЕЮЩИЕ
		|	КОЛИЧЕСТВО(КонтактнаяИнформация.Вид) > 0 ";
	
	Для каждого Объект Из ОбъектыМетаданных Цикл
		НаборТекстаЗапроса.Добавить(СтрЗаменить(ШаблонЗапроса, 
			"#КонтактнаяИнформацияОбъектаМетаданных",
			"Справочник." +  Объект.Метаданные().Имя + ".КонтактнаяИнформация"));
	КонецЦикла;
	
	Запрос = Новый Запрос;
	Запрос.Текст = СтрСоединить(НаборТекстаЗапроса, " ОБЪЕДИНИТЬ ВСЕ ");
	РезультатЗапроса = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");

	Возврат РезультатЗапроса;

КонецФункции

// Описание
// 
// Параметры:
//   ВидКонтактнойИнформации - ДанныеФормыСтруктура
//                           - СправочникОбъект.ВидыКонтактнойИнформации:
//     * Наименование - Строка
//     * Тип  - ПеречислениеСсылка.ТипыКонтактнойИнформации
// 	 
// Возвращаемое значение:
//   Структура:
//   * ЕстьОшибки - Булево
//   * ТекстОшибки - Строка
// 
Функция ПроверитьПараметрыВидаКонтактнойИнформации(ВидКонтактнойИнформации) Экспорт
	
	Результат = Новый Структура("ЕстьОшибки, ТекстОшибки", Ложь, "");
	
	Если НЕ ЗначениеЗаполнено(ВидКонтактнойИнформации.Наименование) Тогда
		Результат.ЕстьОшибки = Истина;
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не заполнено обязательное поле Наименование у вида контактной информации ""%1"".'"),
			Строка(ВидКонтактнойИнформации.ИмяПредопределенногоВида));
		Возврат Результат;
	КонецЕсли;
	
	Если ВидКонтактнойИнформации.ЭтоГруппа Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если НЕ ЗначениеЗаполнено(ВидКонтактнойИнформации.Тип) Тогда
		Результат.ЕстьОшибки = Истина;
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не заполнено обязательное поле Тип у вида контактной информации ""%1"".'"),
			Строка(ВидКонтактнойИнформации.Наименование));
		Возврат Результат;
	КонецЕсли;
	
	Разделитель = "";
	Если ВидКонтактнойИнформации.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		
		Если НЕ ВидКонтактнойИнформации.ТолькоНациональныйАдрес
			И (ВидКонтактнойИнформации.ПроверятьКорректность
			ИЛИ ВидКонтактнойИнформации.СкрыватьНеактуальныеАдреса) Тогда
				Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Некорректно заполнены настройки проверки адреса у вида контактной информации %1.
					| Проверка корректности адреса доступна только для российских адресов'"), Строка(ВидКонтактнойИнформации.Наименование));
					Разделитель = Символы.ПС;
			КонецЕсли;
			
		Если ВидКонтактнойИнформации.РазрешитьВводНесколькихЗначений
			И ВидКонтактнойИнформации.ХранитьИсториюИзменений Тогда
				Результат.ТекстОшибки = Результат.ТекстОшибки + Разделитель + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Некорректно заполнены настройки адреса у вида контактной информации %1.
					| Не допускается возможность ввода нескольких значений контактной информации при включенной истории хранения изменений.'"),
						Строка(ВидКонтактнойИнформации.Наименование));
		КонецЕсли;
	КонецЕсли;
	
	Результат.ЕстьОшибки = ЗначениеЗаполнено(Результат.ТекстОшибки);
	Возврат Результат;
	
КонецФункции

Функция ЕстьПравоДобавления() Экспорт
	Возврат ПравоДоступа("Добавление", Метаданные.Справочники.СтраныМира);
КонецФункции

Процедура ДобавитьКонтактнуюИнформациюДляСсылки(Ссылка, ЗначениеИлиПредставление, ВидКонтактнойИнформации, Дата = Неопределено, Замещать = Истина) Экспорт
	
	ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
	
	НачатьТранзакцию();
	Попытка
	
		Блокировка.Заблокировать();
		Объект = Ссылка.ПолучитьОбъект();
		Объект.Заблокировать();
		ДобавитьКонтактнуюИнформацию(Объект, ЗначениеИлиПредставление, ВидКонтактнойИнформации, Дата, Замещать);
		
		Объект.Записать();
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Параметры:
//   Объект - СправочникОбъект
//   ЗначениеИлиПредставление - Строка
//   ВидКонтактнойИнформации - СправочникСсылка.ВидыКонтактнойИнформации
//   Дата - Неопределено
//   Замещать - Булево
// 
Процедура ДобавитьКонтактнуюИнформацию(Объект, ЗначениеИлиПредставление, ВидКонтактнойИнформации, Знач Дата, Знач Замещать) Экспорт
	
	КонтактнаяИнформация                  = Объект.КонтактнаяИнформация;
	ЭтоКонтактнаяИнформацияВXML           = УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначениеИлиПредставление);
	ЭтоКонтактнаяИнформацияВJSON          = УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(ЗначениеИлиПредставление);
	ЭтоКонтактнаяИнформацияВСтруктуреJSON = ТипЗнч(ЗначениеИлиПредставление) = Тип("Структура");
	СвойстваВидаКонтактнойИнформации      = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ВидКонтактнойИнформации, "Тип, ХранитьИсториюИзменений");
	
	МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(Объект));
	Если МетаданныеОбъекта = Неопределено
		Или МетаданныеОбъекта.ТабличныеЧасти.Найти("КонтактнаяИнформация") = Неопределено Тогда
		ВызватьИсключение НСтр("ru = 'Добавление контактной информации невозможно, у объекта нет таблицы с контактной информацией.'");
	КонецЕсли;
	
	Если ЭтоКонтактнаяИнформацияВСтруктуреJSON Тогда
		
		ОбъектКонтактнойИнформации = ЗначениеИлиПредставление;
		Значение = СтруктураВСтрокуJSON(ЗначениеИлиПредставление);
		ЗначенияПолей = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML(Значение);
		Представление = ОбъектКонтактнойИнформации.Value;
		
	Иначе
		
		Если ЭтоКонтактнаяИнформацияВXML Тогда
			
			ЗначенияПолей = ЗначениеИлиПредставление;
			Значение = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(ЗначениеИлиПредставление, СвойстваВидаКонтактнойИнформации.Тип);
			ОбъектКонтактнойИнформации = JSONВКонтактнуюИнформациюПоПолям(Значение, СвойстваВидаКонтактнойИнформации.Тип);
			Представление = ОбъектКонтактнойИнформации.Value;
			
		ИначеЕсли ЭтоКонтактнаяИнформацияВJSON Тогда
			
			Значение = ЗначениеИлиПредставление;
			ЗначенияПолей = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML(Значение,, СвойстваВидаКонтактнойИнформации.Тип);
			ОбъектКонтактнойИнформации = JSONВКонтактнуюИнформациюПоПолям(Значение, СвойстваВидаКонтактнойИнформации.Тип);
			Представление = ПредставлениеКонтактнойИнформации(ЗначениеИлиПредставление);
			
		Иначе
			ОбъектКонтактнойИнформации = КонтактнаяИнформацияПоПредставлению(ЗначениеИлиПредставление, СвойстваВидаКонтактнойИнформации.Тип);
			Значение = СтруктураВСтрокуJSON(ОбъектКонтактнойИнформации);
			ЗначенияПолей = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML(Значение);
			Представление = ЗначениеИлиПредставление;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Периодическая = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.КонтактнаяИнформацияОбъектаСодержитКолонкуДействуетС(Объект.Ссылка);
	Если Замещать Тогда
		НайденныеСтроки = НайтиСтрокиКонтактнойИнформации(ВидКонтактнойИнформации, Дата, КонтактнаяИнформация, Периодическая);
		Для Каждого СтрокаТабличнойЧасти Из НайденныеСтроки Цикл
			КонтактнаяИнформация.Удалить(СтрокаТабличнойЧасти);
		КонецЦикла;
		СтрокаКонтактнойИнформации = КонтактнаяИнформация.Добавить();
	Иначе
		Если ЗапрещенВводНесколькихЗначений(ВидКонтактнойИнформации, КонтактнаяИнформация, Дата, Периодическая) Тогда
			Если ЭтоКонтактнаяИнформацияВXML Тогда
				СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Найти(ЗначениеИлиПредставление, "ЗначенияПолей");
			ИначеЕсли ЭтоКонтактнаяИнформацияВJSON Тогда
				СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Найти(ЗначениеИлиПредставление, "Значение");
			Иначе
				СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Найти(ЗначениеИлиПредставление, "Представление");
			КонецЕсли;
			Если СтрокаКонтактнойИнформации <> Неопределено Тогда
				Возврат; // Допускается только одно значение этого вида контактной информации.
			КонецЕсли;
		КонецЕсли;
		СтрокаКонтактнойИнформации = КонтактнаяИнформация.Добавить();
	КонецЕсли;
	
	СтрокаКонтактнойИнформации.Значение      = Значение;
	СтрокаКонтактнойИнформации.Представление = Представление;
	СтрокаКонтактнойИнформации.ЗначенияПолей = ЗначенияПолей;
	СтрокаКонтактнойИнформации.Вид           = ВидКонтактнойИнформации;
	СтрокаКонтактнойИнформации.Тип           = СвойстваВидаКонтактнойИнформации.Тип ;
	Если СвойстваВидаКонтактнойИнформации.ХранитьИсториюИзменений И ЗначениеЗаполнено(Дата) Тогда
		СтрокаКонтактнойИнформации.ДействуетС = Дата;
	КонецЕсли;
	
	ЗаполнитьТехническиеПоляКонтактнойИнформации(СтрокаКонтактнойИнформации, ОбъектКонтактнойИнформации, СвойстваВидаКонтактнойИнформации.Тип);
	
КонецПроцедуры

// Параметры:
//   Объект - СправочникОбъект
//   КонтактнаяИнформация - ТаблицаЗначений
//   ОбъектМетаданных - ОбъектМетаданных
//   Замещать - Булево
// 
Процедура УстановитьКонтактнуюИнформациюОбъекта(Объект, КонтактнаяИнформация, ОбъектМетаданных, Знач Замещать) Экспорт
	
	Периодическая = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.КонтактнаяИнформацияОбъектаСодержитКолонкуДействуетС(Объект.Ссылка);
	БезИдентификатораТабличнойЧасти = ОбъектМетаданных.ТабличныеЧасти.КонтактнаяИнформация.Реквизиты.Найти("ИдентификаторСтрокиТабличнойЧасти") = Неопределено;
	
	Для каждого СтрокаКонтактнойИнформации Из КонтактнаяИнформация Цикл
		УправлениеКонтактнойИнформацией.ВосстановитьПустыеЗначениеПредставление(СтрокаКонтактнойИнформации);
	КонецЦикла;
	
	Если Замещать Тогда
		
		Для каждого СтрокаКонтактнойИнформацииОбъекта Из КонтактнаяИнформация Цикл
			
			ДатаОтбора = ?(Периодическая, СтрокаКонтактнойИнформацииОбъекта.Дата, Неопределено);
			НайденныеСтроки = НайтиСтрокиКонтактнойИнформации(СтрокаКонтактнойИнформацииОбъекта.Вид, ДатаОтбора, Объект.КонтактнаяИнформация, Периодическая);
			
			Для каждого Строка Из НайденныеСтроки Цикл
				Объект.КонтактнаяИнформация.Удалить(Строка);
			КонецЦикла;
			
		КонецЦикла;
		
	КонецЕсли;
	
	Для каждого СтрокаКонтактнойИнформацииОбъекта Из КонтактнаяИнформация Цикл
		
		ХранитьИсториюИзменений = Периодическая И СтрокаКонтактнойИнформацииОбъекта.Вид.ХранитьИсториюИзменений;
		
		Если Замещать Тогда
			
			ИдентификаторСтрокиТабличнойЧасти = ?(БезИдентификатораТабличнойЧасти, Неопределено, СтрокаКонтактнойИнформацииОбъекта.ИдентификаторСтрокиТабличнойЧасти);
			Если ЗапрещенВводНесколькихЗначений(СтрокаКонтактнойИнформацииОбъекта.Вид, Объект.КонтактнаяИнформация, СтрокаКонтактнойИнформацииОбъекта.Дата, ХранитьИсториюИзменений, ИдентификаторСтрокиТабличнойЧасти) Тогда
				Продолжить;
			КонецЕсли;
			СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Добавить();
			
		Иначе
			
			Отбор = Новый Структура();
			Отбор.Вставить("Вид", СтрокаКонтактнойИнформацииОбъекта.Вид);
			
			Если ХранитьИсториюИзменений Тогда
				Отбор.Вставить("ДействуетС", СтрокаКонтактнойИнформацииОбъекта.Дата);
				НайденныеСтроки = Объект.КонтактнаяИнформация.НайтиСтроки(Отбор);
			ИначеЕсли ЗначениеЗаполнено(СтрокаКонтактнойИнформацииОбъекта.Значение) Тогда
				Отбор.Вставить("Значение", СтрокаКонтактнойИнформацииОбъекта.Значение);
				НайденныеСтроки = Объект.КонтактнаяИнформация.НайтиСтроки(Отбор);
			Иначе
				Отбор.Вставить("ЗначенияПолей", СтрокаКонтактнойИнформацииОбъекта.ЗначенияПолей);
				НайденныеСтроки = Объект.КонтактнаяИнформация.НайтиСтроки(Отбор);
			КонецЕсли;
			
			Если НЕ ХранитьИсториюИзменений
				И ЗапрещенВводНесколькихЗначений(СтрокаКонтактнойИнформацииОбъекта.Вид, Объект.КонтактнаяИнформация, СтрокаКонтактнойИнформацииОбъекта.Дата, ХранитьИсториюИзменений)
				ИЛИ НайденныеСтроки.Количество() > 0 Тогда
				Продолжить;
			КонецЕсли;
			
			СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Добавить();
			
		КонецЕсли;
		
		ЗаполнитьКонтактнуюИнформациюОбъектаИзСтроки(СтрокаКонтактнойИнформацииОбъекта, ХранитьИсториюИзменений, СтрокаКонтактнойИнформации);
		
	КонецЦикла;

КонецПроцедуры

Процедура УстановитьКонтактнуюИнформациюОбъектаДляСсылки(Ссылка, Знач КонтактнаяИнформация, ОбъектМетаданных, Замещать = Истина) Экспорт
	
	Если КонтактнаяИнформация.Количество() = 0 И Не Замещать Тогда
		Возврат;
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
	
	НачатьТранзакцию();
	Попытка
	
		Блокировка.Заблокировать();
		Объект = Ссылка.ПолучитьОбъект();
		Объект.Заблокировать();
		
		Если КонтактнаяИнформация.Количество() = 0 Тогда
			// Очистка контактной информации пустой таблицей.
			Объект.КонтактнаяИнформация.Очистить();
		Иначе
			УстановитьКонтактнуюИнформациюОбъекта(Объект, КонтактнаяИнформация, ОбъектМетаданных, Замещать);
		КонецЕсли;
		
		Объект.Записать();
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура УстановитьКонтактнуюИнформациюОбъектовДляСсылки(ВладелецКонтактнойИнформации, СтрокиКонтактнойИнформацииОбъекта, Знач Замещать) Экспорт
	
	Ссылка = ВладелецКонтактнойИнформации.Ключ;
	ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Ссылка));
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
	
	НачатьТранзакцию();
	Попытка
	
		Блокировка.Заблокировать();
		Объект = Ссылка.ПолучитьОбъект();
		Объект.Заблокировать();
		
		УстановитьКонтактнуюИнформациюОбъектов(ВладелецКонтактнойИнформации, Объект, СтрокиКонтактнойИнформацииОбъекта, Замещать);
		
		Объект.Записать();
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура УстановитьКонтактнуюИнформациюОбъектов(ВладелецКонтактнойИнформации, Объект, Знач СтрокиКонтактнойИнформацииОбъекта, Знач Замещать) Экспорт
	
	Если Замещать Тогда
		Объект.КонтактнаяИнформация.Очистить();
	КонецЕсли;
	
	Для каждого СтрокаКонтактнойИнформацииОбъекта Из СтрокиКонтактнойИнформацииОбъекта Цикл // СтрокаТаблицыЗначений из см. УправлениеКонтактнойИнформацией.НоваяКонтактнаяИнформация
		
		ХранитьИсториюИзменений = ВладелецКонтактнойИнформации.Значение["Периодическая"] И СтрокаКонтактнойИнформацииОбъекта.Вид.ХранитьИсториюИзменений;
		
		Если Замещать Тогда
			
			Если ЗапрещенВводНесколькихЗначений(СтрокаКонтактнойИнформацииОбъекта.Вид, Объект.КонтактнаяИнформация, СтрокаКонтактнойИнформацииОбъекта.Дата, ХранитьИсториюИзменений) Тогда
				Продолжить;
			КонецЕсли;
			СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Добавить();
			
		Иначе
			
			Отбор = Новый Структура();
			Отбор.Вставить("Вид", СтрокаКонтактнойИнформацииОбъекта.Вид);
			
			Если ХранитьИсториюИзменений Тогда
				Отбор.Вставить("ДействуетС", СтрокаКонтактнойИнформацииОбъекта.Дата);
				НайденныеСтроки = Объект.КонтактнаяИнформация.НайтиСтроки(Отбор);
			ИначеЕсли ЗначениеЗаполнено(СтрокаКонтактнойИнформацииОбъекта.Значение) Тогда
				Отбор.Вставить("Значение", СтрокаКонтактнойИнформацииОбъекта.Значение);
				НайденныеСтроки = Объект.КонтактнаяИнформация.НайтиСтроки(Отбор);
			Иначе
				Отбор.Вставить("ЗначенияПолей", СтрокаКонтактнойИнформацииОбъекта.ЗначенияПолей);
				НайденныеСтроки = Объект.КонтактнаяИнформация.НайтиСтроки(Отбор);
			КонецЕсли;
			
			Если НЕ ХранитьИсториюИзменений
				И ЗапрещенВводНесколькихЗначений(СтрокаКонтактнойИнформацииОбъекта.Вид, Объект.КонтактнаяИнформация, СтрокаКонтактнойИнформацииОбъекта.Дата, ХранитьИсториюИзменений)
				ИЛИ НайденныеСтроки.Количество() > 0 Тогда
				Продолжить;
			КонецЕсли;
			
			СтрокаКонтактнойИнформации = Объект.КонтактнаяИнформация.Добавить();
		КонецЕсли;
		
		ЗаполнитьКонтактнуюИнформациюОбъектаИзСтроки(СтрокаКонтактнойИнформацииОбъекта, ХранитьИсториюИзменений, СтрокаКонтактнойИнформации);
	КонецЦикла;

КонецПроцедуры

Функция ЗапрещенВводНесколькихЗначений(ВидКонтактнойИнформации, КонтактнаяИнформация, Дата, Периодическая, ИдентификаторСтрокиТабличнойЧасти = Неопределено)
	
	Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ВидКонтактнойИнформации, "РазрешитьВводНесколькихЗначений") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Отбор = Новый Структура("Вид", ВидКонтактнойИнформации);
	
	Если ИдентификаторСтрокиТабличнойЧасти <> Неопределено Тогда
		Отбор.Вставить("ИдентификаторСтрокиТабличнойЧасти", ИдентификаторСтрокиТабличнойЧасти);
	КонецЕсли;
	
	Если Периодическая Тогда
		Отбор.Вставить("ДействуетС", Дата);
	КонецЕсли;
	
	НайденныеСтроки = КонтактнаяИнформация.НайтиСтроки(Отбор);
	Возврат НайденныеСтроки.Количество() > 0;
	
КонецФункции

Процедура ЗаполнитьТехническиеПоляКонтактнойИнформации(СтрокаКонтактнойИнформации, Объект, ТипКонтактнойИнформации) Экспорт
	
	// Заполнение дополнительных реквизитов ТЧ.
	Если ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты Тогда
		ЗаполнитьРеквизитыТабличнойЧастиДляАдресаЭлектроннойПочты(СтрокаКонтактнойИнформации, Объект);
		
	ИначеЕсли ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		ЗаполнитьРеквизитыТабличнойЧастиДляАдреса(СтрокаКонтактнойИнформации, Объект);
		
	ИначеЕсли ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Телефон 
		Или ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.Факс Тогда
		ЗаполнитьРеквизитыТабличнойЧастиДляТелефона(СтрокаКонтактнойИнформации, Объект);
		
	ИначеЕсли ТипКонтактнойИнформации = Перечисления.ТипыКонтактнойИнформации.ВебСтраница Тогда
		ЗаполнитьРеквизитыТабличнойЧастиДляВебСтраницы(СтрокаКонтактнойИнформации, Объект);
	КонецЕсли;
	
КонецПроцедуры

Функция НайтиСтрокиКонтактнойИнформации(ВидКонтактнойИнформации, Дата, КонтактнаяИнформация, Периодическая)
	
	Отбор = Новый Структура("Вид", ВидКонтактнойИнформации);
	Если Периодическая Тогда
		Отбор.Вставить("ДействуетС", Дата);
	КонецЕсли;
	НайденныеСтроки = КонтактнаяИнформация.НайтиСтроки(Отбор);
	Возврат НайденныеСтроки;
	
КонецФункции

Процедура ЗаполнитьКонтактнуюИнформациюОбъектаИзСтроки(СтрокаКонтактнойИнформацииОбъекта, Периодическая, СтрокаКонтактнойИнформации)
	
	ЗаполнитьЗначенияСвойств(СтрокаКонтактнойИнформации, СтрокаКонтактнойИнформацииОбъекта);
	Если Периодическая Тогда
		СтрокаКонтактнойИнформации.ДействуетС = СтрокаКонтактнойИнформацииОбъекта.Дата;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(СтрокаКонтактнойИнформации.Значение) Тогда
		ОбъектКонтактнойИнформации = JSONВКонтактнуюИнформациюПоПолям(СтрокаКонтактнойИнформации.Значение, СтрокаКонтактнойИнформацииОбъекта.Тип);
		ЗаполнитьТехническиеПоляКонтактнойИнформации(СтрокаКонтактнойИнформации, ОбъектКонтактнойИнформации, СтрокаКонтактнойИнформацииОбъекта.Тип);
	КонецЕсли;
	
КонецПроцедуры

// Заполняет дополнительные реквизиты табличной части "Контактная информация" для адреса.
//
// Параметры:
//    СтрокаТабличнойЧасти - СтрокаТабличнойЧасти - заполняемая строка табличной части "Контактная информация".
//    Источник             - ОбъектXDTO  - контактная информация.
//
Процедура ЗаполнитьРеквизитыТабличнойЧастиДляАдреса(СтрокаТабличнойЧасти, Адрес)
	
	// Умолчания
	СтрокаТабличнойЧасти.Страна = "";
	СтрокаТабличнойЧасти.Регион = "";
	СтрокаТабличнойЧасти.Город  = "";
	
	Если Адрес.Свойство("Country") Тогда
		СтрокаТабличнойЧасти.Страна =  Адрес.Country;
		
		Если Метаданные.Обработки.Найти("РасширенныйВводКонтактнойИнформации") <> Неопределено Тогда
			Обработки["РасширенныйВводКонтактнойИнформации"].ЗаполнитьРасширенныеРеквизитыТабличнойЧастиДляАдреса(Адрес, СтрокаТабличнойЧасти);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Заполняет дополнительные реквизиты табличной части "Контактная информация" для адреса электронной почты.
//
// Параметры:
//    СтрокаТабличнойЧасти - СтрокаТабличнойЧасти - заполняемая строка табличной части "Контактная информация".
//    Источник             - ОбъектXDTO  - контактная информация.
//
Процедура ЗаполнитьРеквизитыТабличнойЧастиДляАдресаЭлектроннойПочты(СтрокаТабличнойЧасти, Источник)
	
	Результат = ОбщегоНазначенияКлиентСервер.РазобратьСтрокуСПочтовымиАдресами(СтрокаТабличнойЧасти.Представление, Ложь);
	
	Если Результат.Количество() > 0 Тогда
		СтрокаТабличнойЧасти.АдресЭП = Результат[0].Адрес;
		
		Поз = СтрНайти(СтрокаТабличнойЧасти.АдресЭП, "@");
		Если Поз <> 0 Тогда
			СтрокаТабличнойЧасти.ДоменноеИмяСервера = Сред(СтрокаТабличнойЧасти.АдресЭП, Поз+1);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Заполняет дополнительные реквизиты табличной части "Контактная информация" для телефона и факса.
//
// Параметры:
//    СтрокаТабличнойЧасти - СтрокаТабличнойЧасти - заполняемая строка табличной части "Контактная информация".
//    Источник             - ОбъектXDTO  - контактная информация.
//
Процедура ЗаполнитьРеквизитыТабличнойЧастиДляТелефона(СтрокаТабличнойЧасти, Телефон)
	
	Если НЕ ЗначениеЗаполнено(Телефон) Тогда
		Возврат;
	КонецЕсли;
	
	// Умолчания
	СтрокаТабличнойЧасти.НомерТелефонаБезКодов = "";
	СтрокаТабличнойЧасти.НомерТелефона         = "";
	
	КодСтраны     = Телефон.CountryCode;
	КодГорода     = Телефон.AreaCode;
	НомерТелефона = Телефон.Number;
	
	Если СтрНачинаетсяС(КодСтраны, "+") Тогда
		КодСтраны = Сред(КодСтраны, 2);
	КонецЕсли;
	
	Поз = СтрНайти(НомерТелефона, ",");
	Если Поз <> 0 Тогда
		НомерТелефона = Лев(НомерТелефона, Поз-1);
	КонецЕсли;
	
	Поз = СтрНайти(НомерТелефона, Символы.ПС);
	Если Поз <> 0 Тогда
		НомерТелефона = Лев(НомерТелефона, Поз-1);
	КонецЕсли;
	
	СтрокаТабличнойЧасти.НомерТелефонаБезКодов = УбратьРазделителиВНомерТелефона(НомерТелефона);
	СтрокаТабличнойЧасти.НомерТелефона         = УбратьРазделителиВНомерТелефона(Строка(КодСтраны) + КодГорода + НомерТелефона);
	
КонецПроцедуры

// Заполняет дополнительные реквизиты табличной части "Контактная информация" для телефона и факса.
//
// Параметры:
//    СтрокаТабличнойЧасти - СтрокаТабличнойЧасти - заполняемая строка табличной части "Контактная информация".
//    Источник             - Структура
//                         - ОбъектXDTO - контактная информация.
//
Процедура ЗаполнитьРеквизитыТабличнойЧастиДляВебСтраницы(СтрокаТабличнойЧасти, Источник)
	
// Умолчания
	СтрокаТабличнойЧасти.ДоменноеИмяСервера = "";
	
	Если ТипЗнч(Источник) = Тип("Структура") Тогда
		
		Если Источник.Свойство("value") Тогда
			АдресСтрокой = Источник.value;
		КонецЕсли;
		
	Иначе
		
		Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступенМодульЛокализации() Тогда
			МодульУправлениеКонтактнойИнформациейЛокализация = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформациейЛокализация");
			АдресСтрокой = МодульУправлениеКонтактнойИнформациейЛокализация.ЗаполнитьРеквизитыТабличнойЧастиДляВебСтраницы(Источник);
		Иначе
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	// Удалим протокол
	Позиция = СтрНайти(АдресСтрокой, "://");
	АдресСервера = ?(Позиция = 0, АдресСтрокой, Сред(АдресСтрокой, Позиция + 3));
	
	СтрокаТабличнойЧасти.ДоменноеИмяСервера = АдресСервера;
	
КонецПроцедуры

// Убирает разделители в номере телефона.
//
// Параметры:
//    НомерТелефона - Строка - номер телефона или факса.
//
// Возвращаемое значение:
//     Строка - номер телефона или факса без разделителей.
//
Функция УбратьРазделителиВНомерТелефона(Знач НомерТелефона)
	
	Поз = СтрНайти(НомерТелефона, ",");
	Если Поз <> 0 Тогда
		НомерТелефона = Лев(НомерТелефона, Поз-1);
	КонецЕсли;
	
	НомерТелефона = СтрЗаменить(НомерТелефона, "-", "");
	НомерТелефона = СтрЗаменить(НомерТелефона, " ", "");
	НомерТелефона = СтрЗаменить(НомерТелефона, "+", "");
	
	Возврат НомерТелефона;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункцииДляСовместимости

Функция КонтактнаяИнформацияЗаполнена(Знач  КонтактнаяИнформация) Экспорт
	
	Возврат ЕстьЗаполненныеСвойстваКонтактнойИнформации(КонтактнаяИнформация);
	
КонецФункции

Функция ЕстьЗаполненныеСвойстваКонтактнойИнформации(Знач Владелец)
	
	Если Владелец = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если Не Владелец.Свойство("Value") Или Не Владелец.Свойство("Type") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ПустаяСтрока(Владелец.value) Или ПустаяСтрока(Владелец.type) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ЭтоТипАдрес(Владелец.Type) Тогда
		СписокПолейДляПроверки = Новый Массив();
		СписокПолейДляПроверки.Добавить("Country");
	
		Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
			
			МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
			ОбщегоНазначенияКлиентСервер.ДополнитьМассив(СписокПолейДляПроверки, МодульРаботаСАдресамиКлиентСервер.ИменаУровнейАдреса(Владелец, Истина));
			
		КонецЕсли;
		
		Для каждого ИмяПоля Из СписокПолейДляПроверки Цикл
			Если Владелец.Свойство(ИмяПоля) И ЗначениеЗаполнено(Владелец[ИмяПоля]) Тогда
				Возврат Истина;
			КонецЕсли;
		КонецЦикла;
		
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Процедура ЗаменитьВСтруктуреНеопределеноНаПустуюСтроку(СтруктураДляОбхода) Экспорт
	
	Для каждого КлючЗначение Из СтруктураДляОбхода Цикл
		Если ТипЗнч(КлючЗначение.Значение) = Тип("Структура")Тогда
			ЗаменитьВСтруктуреНеопределеноНаПустуюСтроку(СтруктураДляОбхода[КлючЗначение.Ключ]);
		ИначеЕсли КлючЗначение.Значение = Неопределено Тогда
			СтруктураДляОбхода[КлючЗначение.Ключ] = "";
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Функция ПреобразоватьСтрокуВСписокПолей(СтрокаПолей) Экспорт
	
	// XML сериализацию преобразовывать не надо.
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(СтрокаПолей) Тогда
		Возврат СтрокаПолей;
	КонецЕсли;
	
	Результат = Новый СписокЗначений;
	
	СтруктураЗначенийПолей = СтруктураЗначенийПолей(СтрокаПолей);
	Для каждого ЗначениеПоля Из СтруктураЗначенийПолей Цикл
		Результат.Добавить(ЗначениеПоля.Значение, ЗначениеПоля.Ключ);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СтруктураЗначенийПолей(СтрокаПолей, ВидКонтактнойИнформации = Неопределено) Экспорт
	
	Если ВидКонтактнойИнформации = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда
		Результат = УправлениеКонтактнойИнформациейКлиентСервер.СтруктураПолейАдреса();
	ИначеЕсли ВидКонтактнойИнформации = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Телефон") Тогда
		Результат = УправлениеКонтактнойИнформациейКлиентСервер.СтруктураПолейТелефона();
	Иначе
		Результат = Новый Структура;
	КонецЕсли;
	
	ПоследнийЭлемент = Неопределено;
	
	Для Итерация = 1 По СтрЧислоСтрок(СтрокаПолей) Цикл
		ПолученнаяСтрока = СтрПолучитьСтроку(СтрокаПолей, Итерация);
		Если СтрНачинаетсяС(ПолученнаяСтрока, Символы.Таб) Тогда
			Если Результат.Количество() > 0 Тогда
				Результат.Вставить(ПоследнийЭлемент, Результат[ПоследнийЭлемент] + Символы.ПС + Сред(ПолученнаяСтрока, 2));
			КонецЕсли;
		Иначе
			ПозицияСимвола = СтрНайти(ПолученнаяСтрока, "=");
			Если ПозицияСимвола <> 0 Тогда
				НазваниеПоля = Лев(ПолученнаяСтрока, ПозицияСимвола - 1);
				ЗначениеПоля = Сред(ПолученнаяСтрока, ПозицияСимвола + 1);
				Если НазваниеПоля = "Регион" Или НазваниеПоля = "Район" Или НазваниеПоля = "Город" 
					Или НазваниеПоля = "НаселенныйПункт" Или НазваниеПоля = "Улица" Тогда
					Если СтрНайти(СтрокаПолей, НазваниеПоля + "Сокращение") = 0 Тогда
						Результат.Вставить(НазваниеПоля + "Сокращение", АдресноеСокращение(ЗначениеПоля));
					КонецЕсли;
				КонецЕсли;
				Результат.Вставить(НазваниеПоля, ЗначениеПоля);
				ПоследнийЭлемент = НазваниеПоля;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция АдресноеСокращение(Знач ГеографическоеНазвание)
	
	Сокращение = "";
	МассивСлов = СтрРазделить(ГеографическоеНазвание, " ", Ложь);
	Если МассивСлов.Количество() > 1 Тогда
		Сокращение = МассивСлов[МассивСлов.Количество() - 1];
	КонецЕсли;
	
	Возврат Сокращение;
	
КонецФункции

Функция ДесериализацияТелефонаФаксаВJSON(ЗначенияПолей, Представление = "", ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступенМодульЛокализации() 
		И УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
		
			// Общий формат контактной информации.
			МодульУправлениеКонтактнойИнформациейЛокализация = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформациейЛокализация");
			Возврат МодульУправлениеКонтактнойИнформациейЛокализация.КонтактнаяИнформацияИзXML(ЗначенияПолей, ОжидаемыйТип);
		
	КонецЕсли;
	
	Данные = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеНовойКонтактнойИнформации(ОжидаемыйТип);
	
	// Из пар ключ-значение
	СписокЗначенийПолей = Неопределено;
	Если ТипЗнч(ЗначенияПолей)=Тип("СписокЗначений") Тогда
		СписокЗначенийПолей = ЗначенияПолей;
	ИначеЕсли Не ПустаяСтрока(ЗначенияПолей) Тогда
		СписокЗначенийПолей = ПреобразоватьСтрокуВСписокПолей(ЗначенияПолей);
	КонецЕсли;
	
	ПолеПредставления = "";
	Если СписокЗначенийПолей <> Неопределено Тогда
		Для Каждого ЗначениеПоля Из СписокЗначенийПолей Цикл
			Поле = ВРег(ЗначениеПоля.Представление);
			
			Если Поле = "КОДСТРАНЫ" Тогда
				Данные.CountryCode = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "КОДГОРОДА" Тогда
				Данные.AreaCode = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "НОМЕРТЕЛЕФОНА" Тогда
				Данные.Number = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "ДОБАВОЧНЫЙ" Тогда
				Данные.ExtNumber = ЗначениеПоля.Значение;
				
			ИначеЕсли Поле = "ПРЕДСТАВЛЕНИЕ" Тогда
				ПолеПредставления = СокрЛП(ЗначениеПоля.Значение);
				
			КонецЕсли;
			
		КонецЦикла;
		
		// Представление с приоритетами.
		Если Не ПустаяСтрока(Представление) Тогда
			Данные.Value = Представление;
		ИначеЕсли ЗначениеЗаполнено(ПолеПредставления) Тогда
			Данные.Value = ПолеПредставления;
		Иначе
			Данные.Value = ПредставлениеТелефона(Данные);
		КонецЕсли;
		
		Возврат Данные;
	КонецЕсли;
	
	// Разбираем из представления.
	
	// Группы цифр, разделенные символами - не цифрами: страна, город, номер, добавочный. 
	// Добавочный включает в себя непробельные символы слева и справа.
	Позиция = 1;
	Данные.CountryCode  = НайтиПодстрокуЦифр(Представление, Позиция);
	НачалоГорода = Позиция;
	
	Данные.AreaCode  = НайтиПодстрокуЦифр(Представление, Позиция);
	Данные.Number    = НайтиПодстрокуЦифр(Представление, Позиция, " -");
	
	Добавочный = СокрЛП(Сред(Представление, Позиция));
	Если СтрНачинаетсяС(Добавочный, ",") Тогда
		Добавочный = СокрЛ(Сред(Добавочный, 2));
	КонецЕсли;
	Если ВРег(Лев(Добавочный, 3 ))= "ДОБ" Тогда
		Добавочный = СокрЛ(Сред(Добавочный, 4));
	КонецЕсли;
	Если ВРег(Лев(Добавочный, 1 ))= "." Тогда
		Добавочный = СокрЛ(Сред(Добавочный, 2));
	КонецЕсли;
	Данные.ExtNumber = СокрЛП(Добавочный);
	
	// Корректируем возможные ошибки.
	Если ПустаяСтрока(Данные.Number) Тогда
		Если СтрНачинаетсяС(СокрЛ(Представление), "+") Тогда
			// Была попытка явно указать код страны, оставляем страну в покое.
			Данные.AreaCode  = "";
			Данные.Number      = СократитьНеЦифры(Сред(Представление, НачалоГорода));
			Данные.ExtNumber = "";
		Иначе
			Данные.CountryCode  = "";
			Данные.AreaCode  = "";
			Данные.Number      = Представление;
			Данные.ExtNumber = "";
		КонецЕсли;
	КонецЕсли;
	
	Данные.Value = Представление;
	Возврат Данные;
КонецФункции

Функция НайтиПодстрокуЦифр(Текст, ПозицияНачала = Неопределено, ДопустимоКромеЦифр = "") Экспорт
	
	Если ПозицияНачала = Неопределено Тогда
		ПозицияНачала = 1;
	КонецЕсли;
	
	Результат = "";
	ПозицияКонца = СтрДлина(Текст);
	ПоискНачала  = Истина;
	
	Пока ПозицияНачала <= ПозицияКонца Цикл
		Символ = Сред(Текст, ПозицияНачала, 1);
		ЭтоЦифра = Символ >= "0" И Символ <= "9";
		
		Если ПоискНачала Тогда
			Если ЭтоЦифра Тогда
				Результат = Результат + Символ;
				ПоискНачала = Ложь;
			КонецЕсли;
		Иначе
			Если ЭтоЦифра Или СтрНайти(ДопустимоКромеЦифр, Символ) > 0 Тогда
				Результат = Результат + Символ;    
			Иначе
				Прервать;
			КонецЕсли;
		КонецЕсли;
		
		ПозицияНачала = ПозицияНачала + 1;
	КонецЦикла;
	
	// Убираем возможные висящие разделители справа.
	Возврат СократитьНеЦифры(Результат, ДопустимоКромеЦифр, Ложь);
	
КонецФункции

Функция СократитьНеЦифры(Текст, ДопустимоКромеЦифр = "", Направление = Истина) Экспорт
	
	Длина = СтрДлина(Текст);
	Если Направление Тогда
		// Сокращение слева
		Индекс = 1;
		Конец  = 1 + Длина;
		Шаг    = 1;
	Иначе
		// Сокращение справа    
		Индекс = Длина;
		Конец  = 0;
		Шаг    = -1;
	КонецЕсли;
	
	Пока Индекс <> Конец Цикл
		Символ = Сред(Текст, Индекс, 1);
		ЭтоЦифра = (Символ >= "0" И Символ <= "9") Или СтрНайти(ДопустимоКромеЦифр, Символ) = 0;
		Если ЭтоЦифра Тогда
			Прервать;
		КонецЕсли;
		Индекс = Индекс + Шаг;
	КонецЦикла;
	
	Если Направление Тогда
		// Сокращение слева
		Возврат Прав(Текст, Длина - Индекс + 1);
	КонецЕсли;
	
	// Сокращение справа
	Возврат Лев(Текст, Индекс);
	
КонецФункции

#КонецОбласти

Функция КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация, Знач Тип = Неопределено, НастройкиКонвертации = Неопределено) Экспорт
	
	Если НастройкиКонвертации = Неопределено Тогда
		НастройкиКонвертации = УправлениеКонтактнойИнформацией.НастройкиКонвертацииКонтактнойИнформации();
	КонецЕсли;
	
	Если Тип <> Неопределено И ТипЗнч(Тип) <> Тип("ПеречислениеСсылка.ТипыКонтактнойИнформации") Тогда
		Тип = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ТипВидаКонтактнойИнформации(Тип);
	КонецЕсли;
	
	Если Тип = Неопределено Тогда
		Если ТипЗнч(КонтактнаяИнформация) = Тип("Строка") Тогда
			
			Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступенМодульЛокализации()
				 И УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(КонтактнаяИнформация) Тогда
				
				МодульУправлениеКонтактнойИнформациейЛокализация = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформациейЛокализация");
				Тип = МодульУправлениеКонтактнойИнформациейЛокализация.ТипКонтактнойИнформации(КонтактнаяИнформация);
				
			КонецЕсли;
			
		Иначе
			// Локализация
			Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступенМодульЛокализации() Тогда
				МодульУправлениеКонтактнойИнформациейЛокализация = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформациейЛокализация");
				Тип = МодульУправлениеКонтактнойИнформациейЛокализация.ТипКонтактнойИнформацииИзОбъектаXDTO(КонтактнаяИнформация);
			КонецЕсли;
			// Конец Локализация
			
		КонецЕсли;
	КонецЕсли;
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() И Тип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
		
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		Возврат МодульРаботаСАдресами.КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация, Тип, НастройкиКонвертации);
		
	КонецЕсли;
	
	Результат = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеНовойКонтактнойИнформации(Тип);
	
	Если ТипЗнч(КонтактнаяИнформация) = Тип("Структура") Тогда
		
		СоответствиеПолей = Новый Соответствие();
		СоответствиеПолей.Вставить("Представление", "value");
		СоответствиеПолей.Вставить("Комментарий",   "comment");
		
		Если Тип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
			
			СоответствиеПолей.Вставить("КодСтраны",     "countryCode");
			СоответствиеПолей.Вставить("КодГорода",     "areaCode");
			СоответствиеПолей.Вставить("НомерТелефона", "number");
			СоответствиеПолей.Вставить("Добавочный",    "extNumber");
			
		КонецЕсли;
		
		Для каждого ПолеКонтактнойИнформации Из КонтактнаяИнформация Цикл
			ИмяПоля = СоответствиеПолей.Получить(ПолеКонтактнойИнформации.Ключ);
			Если ИмяПоля <> Неопределено Тогда
				Результат[ИмяПоля] = ПолеКонтактнойИнформации.Значение;
			КонецЕсли;
		КонецЦикла;
		
		Возврат Результат;
		
	КонецЕсли;
	
	Если ТипЗнч(КонтактнаяИнформация) = Тип("Строка") 
		И УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВJSON(КонтактнаяИнформация) Тогда
			Возврат JSONВКонтактнуюИнформациюПоПолям(КонтактнаяИнформация, Тип);
	КонецЕсли;
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступенМодульЛокализации() Тогда
		МодульУправлениеКонтактнойИнформациейЛокализация = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформациейЛокализация");
		Результат = МодульУправлениеКонтактнойИнформациейЛокализация.КонтактнаяИнформацияВСтруктуруJSON(КонтактнаяИнформация, Тип, НастройкиКонвертации);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Значение - Структура
// 
// Возвращаемое значение:
//  Строка
//
Функция СтруктураВСтрокуJSON(Значение) Экспорт
	
	КонтактнаяИнформацияПоПолям = Новый Структура;
	
	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();
	
	Для каждого ЭлементСтруктуры Из Значение Цикл
		Если ПустаяСтрока(ЭлементСтруктуры.Значение) И ЭлементСтруктуры.Значение <> "" Тогда
			// Преобразуем неопределено, NULL и незначащие символы в пустую строку.
			Значение[ЭлементСтруктуры.Ключ] = "";
		ИначеЕсли ТипЗнч(ЭлементСтруктуры.Значение) = Тип("Массив") Тогда
			
			Индекс = ЭлементСтруктуры.Значение.Количество() - 1;
			Пока Индекс >=0 Цикл
				
				Если СтрСравнить(ЭлементСтруктуры.Ключ, "apartments") = 0 
					Или СтрСравнить(ЭлементСтруктуры.Ключ, "buildings") = 0 Тогда
						ПроверяемоеЗначение = ЭлементСтруктуры.Значение[Индекс].number;
				ИначеЕсли СтрСравнить(ЭлементСтруктуры.Ключ, "admLevels") = 0 
					Или СтрСравнить(ЭлементСтруктуры.Ключ, "munLevels") = 0 Тогда
						ПроверяемоеЗначение = ЭлементСтруктуры.Значение[Индекс];
				Иначе
					Индекс = Индекс - 1;
					Продолжить;
				КонецЕсли;
				
				Если ПустаяСтрока(ПроверяемоеЗначение) Тогда
					ЭлементСтруктуры.Значение.Удалить(Индекс);
				КонецЕсли;
				
				Индекс = Индекс - 1;
			КонецЦикла;
			
		КонецЕсли;
		Если ЗначениеЗаполнено(ЭлементСтруктуры.Значение) Тогда
			КонтактнаяИнформацияПоПолям.Вставить(ЭлементСтруктуры.Ключ, ЭлементСтруктуры.Значение);
		КонецЕсли;
	КонецЦикла;
	
	Если КонтактнаяИнформацияПоПолям.Свойство("area") И УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		МодульРаботаСАдресами.УстановкаТипаОбластьКемеровскойОбласти(КонтактнаяИнформацияПоПолям);
		
	КонецЕсли;
	
	ЗаписатьJSON(ЗаписьJSON, КонтактнаяИнформацияПоПолям,, "АдаптацияПолейКонтактнойИнформации", УправлениеКонтактнойИнформациейСлужебный);
	
	Возврат ЗаписьJSON.Закрыть();
	
КонецФункции

Функция АдаптацияПолейКонтактнойИнформации(Свойство, Значение, ДополнительныеПараметрыФункцииПреобразования, Отказ) Экспорт
	
	Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
		Возврат Строка(Значение);
	КонецЕсли;
	
КонецФункции

// Параметры:
//  Значение - Строка 
//  ТипКонтактнойИнформации - СправочникСсылка.ВидыКонтактнойИнформации
//                          - Структура 
//                          - ПеречислениеСсылка.ТипыКонтактнойИнформации
//
// Возвращаемое значение:
//   см. РаботаСАдресамиКлиентСервер.ОписаниеНовойКонтактнойИнформации
//
Функция JSONВКонтактнуюИнформациюПоПолям(Знач Значение, ТипКонтактнойИнформации) Экспорт
	
	Значение = СтрЗаменить(Значение, "\R\N", "\r\n"); // исправление перевода строки
	
	Результат = Новый Структура();
	
	КонтактнаяИнформация = СтрокуJSONВСтруктуру(Значение);
	
	Если Не ЗначениеЗаполнено(ТипКонтактнойИнформации) Тогда
		Если КонтактнаяИнформация.Свойство("type") Тогда
			ТипКонтактнойИнформации = ТипКонтактнойИнформацииИзСтроки(КонтактнаяИнформация.type);
		КонецЕсли;
	КонецЕсли;
	
	Если УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		МодульРаботаСАдресамиКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресамиКлиентСервер");
		Результат = МодульРаботаСАдресамиКлиентСервер.ОписаниеНовойКонтактнойИнформации(ТипКонтактнойИнформации);
	Иначе
		Результат = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеНовойКонтактнойИнформации(ТипКонтактнойИнформации);
	КонецЕсли;
	
	Если КонтактнаяИнформация.Свойство("area") И УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ДоступныМодулиРаботаСАдресами() Тогда
		
		МодульРаботаСАдресами = ОбщегоНазначения.ОбщийМодуль("РаботаСАдресами");
		МодульРаботаСАдресами.УстановкаТипаОбластьКемеровскойОбласти(КонтактнаяИнформация);
		
	КонецЕсли;
		
	ЗаполнитьЗначенияСвойств(Результат, КонтактнаяИнформация);
	
	Возврат Результат;
	
КонецФункции

Функция ТипКонтактнойИнформацииИзСтроки(Знач ТипКонтактнойИнформацииСтрокой)
	
	Результат = Новый Соответствие;
	Результат.Вставить("Адрес", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес"));
	Результат.Вставить("Телефон", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Телефон"));
	Результат.Вставить("АдресЭлектроннойПочты", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты"));
	Результат.Вставить("Skype", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Skype"));
	Результат.Вставить("ВебСтраница", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.ВебСтраница"));
	Результат.Вставить("Факс", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Факс"));
	Результат.Вставить("Другое", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Другое"));
	
	Возврат Результат[ТипКонтактнойИнформацииСтрокой];
	
КонецФункции

Функция СтрокуJSONВСтруктуру(Значение) Экспорт
	
	ЧтениеJSON = Новый ЧтениеJSON;
	ЧтениеJSON.УстановитьСтроку(Значение);
	
	Попытка
		Результат = ПрочитатьJSON(ЧтениеJSON,,,, "ВосстановлениеПолейКонтактнойИнформации", УправлениеКонтактнойИнформациейСлужебный);
	Исключение
		ТекстОшибки = НСтр("ru = 'Ошибка конвертации контактной информации из формата JSON.'");
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			УровеньЖурналаРегистрации.Ошибка,,,
			ТекстОшибки + Символы.ПС + Строка(Значение));
		Результат = Новый Структура;
		
	КонецПопытки;
	
	ЧтениеJSON.Закрыть();
	
	Возврат Результат;
	
КонецФункции

Функция ВосстановлениеПолейКонтактнойИнформации(Свойство, Значение, ДополнительныеПараметрыФункцииПреобразования) Экспорт
	
	Если СтрЗаканчиваетсяНа(ВРег(Свойство), "ID") И СтрДлина(Значение) = 36 Тогда
		Возврат Новый УникальныйИдентификатор(Значение);
	КонецЕсли;
	
	Если СтрСравнить(Свойство, "houseType") = 0 Тогда
		Возврат ТРег(Значение);
	КонецЕсли;
	
	Если (СтрСравнить(Свойство, "buildings") = 0
		ИЛИ СтрСравнить(Свойство, "apartments") = 0)
		И ТипЗнч(Значение) = Тип("Массив") Тогда
		Для Каждого ЗначениеМассива Из Значение Цикл
			ЗначениеМассива.type = ТРег(ЗначениеМассива.type);
		КонецЦикла;
		
		Возврат Значение;
	КонецЕсли;
	
КонецФункции

Функция НомерТелефонаСоответствуетМаске(НомерТелефона, Маска) Экспорт 
	
	КоличествоСимволов = СтрДлина(НомерТелефона);
	
	Если КоличествоСимволов <> СтрДлина(Маска) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ПроверяемыеСимволыМаски = ПроверяемыеСимволыМаски();
	
	Для НомерСимвола = 1 По КоличествоСимволов Цикл
		СимволМаски = Сред(Маска, НомерСимвола, 1);
		СимволНомераТелефона = Сред(НомерТелефона, НомерСимвола, 1);
		Если СимволМаски = "9"  Тогда
			Если НЕ СтроковыеФункцииКлиентСервер.ТолькоЦифрыВСтроке(СимволНомераТелефона,,Ложь) Тогда 
				Возврат Ложь;  
			Иначе
				Продолжить;
			КонецЕсли;		
		КонецЕсли;
			
		Если ПроверяемыеСимволыМаски.Получить(СимволМаски) = Неопределено И СимволМаски <> СимволНомераТелефона Тогда
			Возврат Ложь;	
		КонецЕсли;		
	КонецЦикла; 
	
	Возврат Истина;
	
КонецФункции

Функция ПроверяемыеСимволыМаски()
	
	СимволыМаски = Новый Соответствие;
	
	СимволыМаски.Вставить( "!", Истина);
	СимволыМаски.Вставить( "#", Истина);
	СимволыМаски.Вставить( "N", Истина);
	СимволыМаски.Вставить( "U", Истина);
	СимволыМаски.Вставить( "X", Истина);
	СимволыМаски.Вставить( "h", Истина);
	СимволыМаски.Вставить( "@", Истина);
	
	Возврат СимволыМаски;
	
КонецФункции

#КонецОбласти